Service Worker 入门
什么是 Service Worker
Server Worker 可以理解为是一个特殊的 JavaScript 脚本
由浏览器在后台运行,由页面触发又独立于页面的 JavaScript 脚本。可以提供推送通知、后台同步、处理页面请求提供缓存等功能。优化了页面的离线体验。
特点:
-
是一个可编程的网络代理,可以处理网络请求
-
独立异步的线程。与页面通过
postMessage
交互,由页面去控制 DOM -
会自动按需停止和启动。涉及持久化时可以使用 IndexedDB API
-
大量使用 Promise API
-
事件驱动
生命周期
一个 Service Worker 实现请求缓存的例子
准备
-
确定浏览器支持
-
站点部署需要支持 HTTPS,开发时可以直接用 localhost
-
入口文件:
index.js
(注册sw.js
) -
Service Worker 文件:
sw.js
(实现具体功能, 名字可以任意, 例如 service-worker.js)
注册 Servcie Worker 文件 sw.js
入口文件 index.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js').then(function (registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function (err) {
// Registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
Service worker 文件 sw.js 所在的路径决定了接收 fetch 事件的作用域
实现 Service Worker 文件 sw.js
Service Worker
文件 sw.js 可以使用一些专有关键字:实例self
,缓存caches
。通过self
可以监听特定的事件addEventListener
。
测试
Service Worker 文件 sw.js
console.log('hello from Service Worker', self, caches)
添加缓存
在intall
时启用缓存,在fetch
时先检查缓存是否匹配。当用户打开或刷新页面时,会触发fetch
事件。
Service Worker 文件 sw.js
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
'/',
'/asset',
'/main.css',
'/main.js',
];
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function (cache) {
return cache.addAll(urlsToCache);
})
)
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
// Cache hit - return response
if (response) {
return response;
} else {
return fetch(event.request);
}
})
)
});
-
查看安装的 Service Worker
-
Devtools > Application > Application > Service Workers
-
chrome://inspect/#service-workers
-
-
查看添加的缓存
- Devtools > Application > Cache Storage >
CACHE_NAME
- Devtools > Application > Cache Storage >
缓存的内容需要调用
caches
接口来更新和删除,也可能直接被浏览器清理。
动态添加缓存
成功的请求,拷贝后放入缓存
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
if (response) {
return response;
} else {
return fetch(event.request).then(function (response) {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need to
// clone it so we have two streams.
const responseToCache = response.clone();
caches.open(CACHE_NAME).then(function (cache) {
cache.put(event.request, responseToCache);
});
return response;
})
}
})
)
})
缓存策略
可以对event.request
等条件进行过滤,按需添加缓存。
根据 Network,Cache,update 和 refresh 的组合和优先级形成不同的缓存策略。
Workbox: 构建 Progressive Web Apps(PWA) 的库
配合框架使用
前端框架脚手架的 PWA 库可以借助 workbox 自动生成 Service Worker / PWA 相关代码。
一般默认在生产模式下启用。使用缓存优先策略。缓存静态文件(static site assets),不会缓存跨域的请求如 API requests,images,embeds 等。
-
Vue-cli: @vue/cli-plugin-pwa
vue add pwa
-
Create React App: Making a Progressive Web App
- npx create-react-app my-app --template cra-template-pwa
- Switch
serviceWorker.unregister()
toserviceWorker.register()
-
Nexst.js: next-pwa
npm i next-pwa
next.config.js(默认开发和生产模式都会启用)
const withPWA = require('next-pwa'); module.exports = withPWA({ pwa: { // disable: process.env.NODE_ENV === 'development', // dest: 'public' } });