本文旨在帮你快速了解 service worker 的基本知识点,让你对 service worker 有一个大致的了解。为以后开发一个简单的 PWA 应用打下基础。

关于 service worker 的几个基本知识点

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 事件回调函数中,你可以:

  1. 打开一组缓存
  2. 缓存所需文件
  3. 检查所有需要的文件是否都已被缓存
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 的流程大致如下:

  1. 修改 service worker 的脚本文件。当用户再次访问页面时,浏览器会尝试重新下载脚本文件。并与之前的版本比对。一旦发现文件内容不一致,就会进入更新流程。
  2. 新的 service worker 会被启动并触发 install 事件。
  3. 此时页面的控制器权还在老版 service worker 手中,而新版 service worker 进入 waiting 状态。
  4. 当前页面被关闭,老版 service worker 被终止。(注意:刷新页面不足以触发新老 service worker 交接)
  5. 用户再次访问页面,新版 service worker 被启动。触发 activate 事件。

注:要想在新版 service worker 安装完成后立刻接管页面而不必等到下一次加载页面。可以调用 self.skipWaiting() 方法跳过等待状态。

以上就是本篇的全部内容。希望能够帮你对 service worker 建立一个大致的了解。在下一篇文章中我会编写一个完整的例子。敬请期待!

参考资料