PWA实战准备篇二
上一篇文章主要是对Web Push和Service Worker运行起来的方法,在正式开始PWA实战篇之前,还会有两次的准备篇,本次文章内容包括两点
- 让我们的网站保持同步
- TypeScript入门
需要准备第一点的原因是,对于一个IM应用,离线的情况是不可避免的,既然我们PWA能够让用户离线可用,那么为了确保用户离线情况发送消息,或者Http请求能够发送给服务器,就需要一个新的API:BackgroundSync
至于第二点,为什么选用了TypeScript作为开发的语言
- TypeScript 是 JavaScript 的超集
- TypeScript 使得抽象清晰可见
- TypeScript 使代码更容易阅读和理解
哎,其实这三点是别人翻译的,站在我的角度,原因就是:爽,舒服
让我们的网站保持同步
平常我们开发网页的时候,对于无网的情况几乎无法处理,因为随着网络的断开,请求也就会随之中止。而且也没有一种机制能够维持这种机制,等有网络的情况再把请求发出去。
利用Service worker的BackgroundSync我们可以实现上面的两个功能,基本流程:
- 在Service Worker中监听sync事件
- 浏览器中发起后台同步的sync
- 触发sync事件,监听的回调中进行操作,例如向后台发送请求
- 最后Service Worker中对服务端返回的数据进行处理
需要注意的是:就算你把网页关闭了,这个任务也是能够继续跑的
看一下html结构
<!DOCTYPE html>
<html>
<head>
<meta chatset="UTF-8">
<title>Home Page</title>
</head>
<body>
<div id="offline"></div>
<div id="header">
<h1>Processive Times</h1>
<br>
<p>Please send us any questions you may have</p>
</div>
<div id="container">
<div class="contact-form">
<input type="text" id="name" name="name" placeholder="Your name">
<br>
<input type="email" id="email" name="email" placeholder="Email Address">
<br>
<input type="text" id="subject" name="subject" placeholder="=Subject">
<br>
<input type="text" id="message" name="message" placeholder="Your Message">
<br>
<button id="submit"></button>
</div>
</div>
<script type="text/javascript" src="./idb-keyval.js"></script>
<script type="text/javascript">
if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.register('./sw.js')
.then(registeration => navigator.serviceWorker.ready)
.then(registeration => {
document.getElementById('submit').addEventListerner('click', ()=> {
registeration.sync.register('contact-email').then(() => {
var payload = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
subject: document.getElementById('subject').value,
message: document.getElementById('message').value
};
idbKeyval.set('sendMessage', payload);
});
});
})
}
</script>
</body>
</html>
和我们之前的例子差不多,但是加了一个idb-keyval的库,然后对submit做了一个事件监听,这么做的原因Service Worker是无法访问dom元素的,那我们如何把元素传递给Service Worker呢?一种就是IndexedDB,另外还可以使用缓存,这样我们把值存到IndexDB,当sync事件触发的时候,就可以访问到这个值。
然后我们看sw.js
importScripts('./idb-keyval.js');
self.addEventListener('sync', (event) => {
if (event.tag === 'contact-email') {
event.waitUtil(
idbKeyval.get('sendMessage').then(value => {
fetch('/sendMessage/', {
method: 'POST',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify(value)
}).then(response => {
if (response.status >= 200) {
idbKeyval.delete('sendMessage');
}
});
});
)
}
});
首先导入idb-keyval,然后检查当前事件标签是否一直,然后使用fetch API把value发送到服务器。
这里需要注意的是,如果上面的步骤成功,没啥问题,但是如果有任何原因导致fetch失败,后台同步的API会再次尝试,他内置了智能的重试功能,来应对promise可能失败的原因。
最后看一起服务器的代码
const express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors')
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static('./public'));
app.post('/sendMessage', function(req, res) {
console.log(req.body);
console.log(req.params);
res.sendStatus(200);
});
app.listen(3111, function(){
console.log('listen on 3111');
});
最后用一个视频来结束本节
TypeScript入门
基础类型
布尔值
let isDone: boolean = false;
数字
let literal: number = 100;
字符串
let str: string= 'hello';
数组
有两种方式:一是可以在元素类型后面增加[],例如:let list: number[] = [1, 2, 3]
第二种是使用数组泛型,例如:let list:Array<number> = [1, 2, 3]
元组Tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比 如,你可以定义一对值分别为 string 和 number 类型的元组let x: [string, number]; x = ['hi', 11]; //正确 x = [11, 'hi']; //错误
我们可以正常访问数据,但是当数组越界的时候,会使用联合类型来替代,这里的联合类型就是(string | number)
枚举
这个类型是对JavaScript标准数据类型的一个补充,给一组数值取一个名字
enum Color {Red, Green, Blue}; let c: Color = Color.Red;
任意值
在JavaScript中,我们声明一个变量的时候,其实就是任意类型的值。在TypeScript中可以使用any来标记这些变量
let notSure: any = 4; notSure = false; let list: any[] = [1, true, 'free']; list[1] = 100;
空值
某种程度上来说,空值和任意值是相反的
function warnUser(): void { console.log(11); }
表示函数没有返回,声明一个void的变量没有什么意义,因为这种变量只能赋值为undefined和null
Null和Undefined, 这两个也是有自己的类型的
let u: undefined = undefined; let n: null = null;
Never
never类型表示的是那些永不保存的值的类型。never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
function error(message: string): never { throw new Error(meesage); } function fail () { return error('somthind failed'); }
Object 类型
object表示非原始类型,也就是除了number、string、boolean、symbol、null或undefined之外的类型
declare function create(o: object | null): void; create({ prop: 0 }); // OK create(null); // OK create(42); // Error
类型断言
类型断言就是JavaScript中的类型转换,基本格式可以用尖括号和as两种语法
let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; let strLength2: number = (someValue as string).length;