本文旨在帮你快速了解 service worker 的基本知识点,让你对 service worker 有一个大致的了解。为以后开发一个简单的 PWA 应用打下基础。
关于 service worker 的几个基本知识点
- 它是一个可编程的网络代理,让你可以控制页面请求的处理方式。
- 它是一个 JavaScript Worker,因此它无法直接操作 DOM。但可以通过 postMessage 接口与页面通信。同时,service worker 中的代码不会阻塞页面响应。
- 它在闲置时被终止,在需要时被启动。并不是常驻内存。因此你不能在
onfetch或是onmessage回调中依赖全局状态。 - 被设计成完全异步。因此在 service worker 中无法使用同步 API (例如同步 XHR,localStorage等)。接口重度依赖于 promise。
- 只能在 HTTPS 页面加载(唯一的例外:localhost/127.0.0.1,方便调试)。
Service worker 的作用域
一个 service worker 的默认作用域是这个 service worker 脚本所在的目录。例如 https://example.com/sw.js 脚本默认就是 https://example.com 下的所有页面。
你也可以在注册 service worker 时明确指定作用域:
navigator.serviceWorker.register('sw.js', {
scope: './abc'
});
假设以上代码在 https://example.com 页面里执行,则意味着该 service worker 的作用域就是 https://example.com/abc 下的页面。
我们把页面、workers 以及 shared workers 统称为 clients。你的 service worker 只能控制其作用域范围内的 clients。
你可以通过检查 navigator.serviceWorker.controller 属性来判断某个 client 是否受控于 service worker 之下。
Service worker 的生命周期
Service worker 的生命周期与页面的生命周期是完全独立的。

1. 注册 service worker
在 register() 时传入的 service worker 脚本的路径决定了此 service worker 的作用域。
// 检测浏览器是否支持 service worker API
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
}
2. install 事件
在注册 service worker 之后,从 service worker 的视角来看。它收到的第一个事件就是 install 事件。在 install 事件回调函数中,你可以:
- 打开一组缓存
- 缓存所需文件
- 检查所有需要的文件是否都已被缓存
var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
'/',
'/styles/main.css',
'/script/main.js'
];
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
);
});
3. activate 事件
在 activate 事件回调中通常要做的工作就是缓存管理。此时可以安全的清理之前版本 service worker 创建的缓存内容。
4. fetch 事件
安装完成以后,当页面发起网络请求时,会触发 service worker 的 fetch 事件。在事件回调函数中你可以决定如何处理该请求。
例如,优先从缓存中加载:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// 命中缓存,直接把缓存的内容返回给页面
if (response) {
return response;
}
// 否则,请求网络
return fetch(event.request);
}
)
);
});
更新 service worker
更新一个 service worker 的流程大致如下:
- 修改 service worker 的脚本文件。当用户再次访问页面时,浏览器会尝试重新下载脚本文件。并与之前的版本比对。一旦发现文件内容不一致,就会进入更新流程。
- 新的 service worker 会被启动并触发
install事件。 - 此时页面的控制器权还在老版 service worker 手中,而新版 service worker 进入
waiting状态。 - 当前页面被关闭,老版 service worker 被终止。(注意:刷新页面不足以触发新老 service worker 交接)
- 用户再次访问页面,新版 service worker 被启动。触发
activate事件。
注:要想在新版 service worker 安装完成后立刻接管页面而不必等到下一次加载页面。可以调用 self.skipWaiting() 方法跳过等待状态。
以上就是本篇的全部内容。希望能够帮你对 service worker 建立一个大致的了解。在下一篇文章中我会编写一个完整的例子。敬请期待!