引言
Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。Service Worker 是 PWA 中的重要一部分。Service Worker 可以监听当前域下的功能性事件,比如拦截和处理网络请求、推送通知(push)、后台同步(sync),今天我们来了解一下 Service Worker
什么是 Service Worker
Service worker (简称 SW) 是一个注册在指定源和路径下的事件驱动 Worker。它采用 JavaScript 控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。
开始编写一个简单的 SW
注册 Service Worker
首先,我们通过 js 代码调用浏览器的 api,注册 SW,告诉浏览器 SW 文件的位置,Service Worker 支持 promise,所以写起来非常方便
// main.js
if (navigator.serviceWorker) {
window.addEventListener('DOMContentLoaded', () => {
navigator.serviceWorker
.register('sw.js')
.then(function(swReg) {
console.log('sucess ~', swReg);
})
.catch(function(error) {
console.error('fail !', error);
})
})
}
sw 存在作用域的概念,上面注册的作用域为 '/',如果注册的 js 文件地址为 'a/sw.js',则 sw 的作用域为 '/a'
开始缓存
接下来的代码编写主要集中在 sw.js (sw 加载的 js 文件) 文件中,在 Service Worker 安装过程中,我们进行数据的缓存。缓存文件的重要角色是浏览器的 Cache API,将数据缓存下来。
const cacheName = 'myCache'
const cacheArray = [
'/index.html',
'/index.css',
'/main.js'
]
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
// 打开一个 Cache 对象
caches.open(CACHE_NAME)
.then(function(cache) {
// 缓存数组中的内容
return cache.addAll(urlsToCache);
})
)
})
因为一个 Worker是使用一个构造函数创建的一个对象运行一个命名的JavaScript文件。这个文件包含将在工作线程中运行的代码,运行在另一个全局上下文中,不同于当前的window。在 sw.js 中,无法使用 window、操作 DOM 等,使用 self 关键字,来实引用 DedicatedWorkerGlobalScope。如果所有文件都成功缓存,则将安装 Service Worker。 如有任何文件无法下载,则安装步骤将失败。也意味着 Service Worker 启动失败
event.waitUntil
确保浏览器关闭也仍然能够执行
缓存和代理请求
Service Worker 能够实现离线功能,主要是拥有代理请求的功能,我们能够在请求的时候有自己的操作空间,请求优先,请求失败从 Cache 读取缓存;请求成功,更新缓存。
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
return event.respondWith(
fetch(event.request).catch(() =>
caches.match(OFFLINE_URL))
)
}
})
event.respondWith
接收推送消息
在 sw.js 的内部通过事件监听的方式执行对应的回调函数,接收外部的推送信息,只需要添加 push 事件监听即可
self.addEventListener('push', function(event) {
const options = {
body: 'Yay it works.',
icon: 'images/icon.png',
badge: 'images/badge.png'
}
self.registration.showNotification(title, options);
})
消息推送,配合 Web Server For Chrome 更方便~
开启后台同步功能
在浏览器无网络请情况下,服务端推送消息,浏览器无法接收到,但是当网络连通时,浏览器就可以接收到服务端推送的信息。浏览器的请求也可以实现同样的功能,通过特殊的方式发送请求,网络连通时,请求才会发出去。
// 请求
navigator.serviceWorker.ready.then((registration) => {
// 区分不同的事件
const tag = 'tag';
registration.sync.register(tag).then(() => {
// do something...
})
})
// 事件监听
// sw.js
self.addEventListener('sync', function (e) {
console.log(e.tag === 'tag') // true
e.waitUntil(...)
})
工作周期
- 初始化阶段: 页面加载、解析 Service Worker 的 js 文件
- 安装阶段: 安装 Service Worker ,通常在安装中执行缓存
- 工作阶段:监听各种事件,执行工作
- 待机阶段:网页关闭,Service Worker 在浏览器处于"静默"的状态,有事件同送等重新开始,随后再次"静默"
- 更新阶段:新的 sw 触发 install 事件,旧的 sw 出发 activate 事件
Firebase 云信息传递 (FCM)
Firebase 云信息传递 (FCM) 是一种跨平台消息传递解决方案,可供您免费、可靠地传递消息。可以发送通知消息以再次吸引用户并留住他们。在即时通讯等使用情形中,一条消息可将最多 4KB 的有效负载传送至客户端应用。
浏览器的 Service Worker 的消息推送主要依赖 FCM,服务端消息推送传递到 FCM,然后再由 FCM 推送到客户端。
参考链接: