Service Worker

    Service Worker 是一个后台运行的脚本,充当一个代理服务器,拦截用户发出的网络请求,比如加载脚本和图片。Service Worker 可以修改用户的请求,或者直接向用户发出回应,不用联系服务器,这使得用户可以在离线情况下使用网络应用。它还可以在本地缓存资源文件,直接从缓存加载文件,因此可以加快访问速度。

    上面代码确认浏览器支持 Service Worker 以后,会注册一个 Service Worker。

    为了节省内存,Service worker 在不使用的时候是休眠的。它也不会保存数据,所以重新启动的时候,为了拿到数据,最好把数据放在 IndexedDb 里面。

    Service Worker 是事件驱动的。

    1. event.waitUntil(
    2. if (event.request.url.includes('/product') {
    3. let productId = event.data.productId
    4. let productCount = getProductData(productId)
    5. indexedDB.open('store', 1, (db) => {
    6. let productStore = db.createObjectStore('products', { keyPath: 'id' })
    7. productStore.put({ id: productId, count: ++productCount })
    8. })
    9. })
    10. )

    Service Worker 不能直接操作 DOM。

    使用 service worker 的第一步,就是告诉浏览器,需要注册一个 service worker 脚本。

    1. navigator.serviceWorker.register('sw.js'.then(() => {
    2. console.info('注册成功')
    3. }).catch((err) => {
    4. console.error('注册失败')
    5. })

    上面代码的sw.js就是需要浏览器注册的 service worker 脚本。注意,这个脚本必须与当前网址同域,service worker 不支持跨与脚本。另外,必须是从 HTTPS 协议加载的。

    默认情况下,Service worker 只对根目录/生效,如果要改变生效范围,可以运行下面的代码。

    登记后,就会触发install事件。service worker 脚本需要监听这个事件。

    1. self.addEventListener('install', event => {
    2. event.waitUntil(() => console.info('安装完成'))
    3. })

    event.waitUntil()方法为事件完成后指定回调函数。

    1. self.addEventListener('install', (event) => {
    2. let CACHE_NAME = 'xyz-cache'
    3. let urlsToCache = [
    4. '/',
    5. '/styles/main.css',
    6. '/scripts/bundle.js'
    7. ]
    8. event.waitUntil(
    9. caches.open(CACHE_NAME)
    10. })

    安装完成后,service worker 就会等待激活。

    1. self.addEventListener('activate', (event) => {
    2. event.waitUntil(
    3. self.clients.matchAll().then ( (client) => {
    4. client.postMessage({
    5. msg: 'Hey, from service worker! I\'m listening to your fetch requests.',
    6. source: 'service-worker'
    7. })
    8. })
    9. )
    10. })

    上面代码中,Service Worker 监听activate事件,然后向客户端发送一条信息。

    1. this.addEventListener('message', (data) => {
    2. if (data.source == 'service-worker') {
    3. console.log(data.msg)
    4. }
    5. })
    • , by Ryan Miller