service worker介绍

原文:Service workers explained

译者:neal1991

welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me

LICENSE: MIT

那么它是什么?

Service worker正是被开发用于解决web平台上经常出现的问题和疑虑,包括:

  • 无法解释(Extensible Web Manifesto 中)的HTTP缓存以及高级HTTP交互比如HTML5 AppCache。
  • 难以自然地构建一个离线优先地web应用。
  • 缺乏可以利用很多提出功能的上下文执行。

我们也注意到了声明解决方案(Google Gears, Dojo Offline以及HTML5 AppCache都没能实现他们的承诺。每个连续的仅有声明的方法都以相同的方式失败了,所以service worker采取了一个不同的设计方法:一个可以用开发者牢牢把控的重要系统:

Service worker就好像它的内部有一个有一个shared worker :

  • 在它自己的全局脚本上下文中运行(通常是在它自己的线程中)
  • 不会和特定的页面绑定
  • 不能够访问DOM

不像shared worker,它:

  • 即使没有页面也能够运行
  • 如果不使用的话可以终止,还可以再次运行当需要的时候(比如,他不是事件驱动的)
  • 拥有一个定义的升级模式
  • 只允许HTTPS(更多的是在这一点上)

我们可以利用service workers:

  • 利用网络拦截可以让让网站更快以及/或者支持离线使用
  • 作为其它’background’功能的基础比如消息推送以及后台同步

开始

首先你需要注册一个service worker:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/my-app/sw.js').then(function(reg) {
    console.log('Yey!', reg);
  }).catch(function(err) {
    console.log('Boo!', err);
  });
}

在这个例子中,/my-app/sw.js就是service worker脚本的位置,并且它控制那些页面的URL以/my-app/开头。

.register返回一个promise。如果你以前没接触过promise的话,可以看看HTML5Rocks article。

一些限制:

  • 注册页面必须安全地提供(没有证书错误的HTTPS)
  • service worker和页面必须同源,尽管你可使用 importScripts去导入其它地方的脚本

  • 作为必须的范围

只有你说HTTPS?

使用service worker,你可以劫持请求,进行不同的响应,并且过滤响应。这些功能都很强大。尽管你可以将这些能力用在好的地方,但是中间人可能不会。为了避免这一点,你只能在HTTPS上提供的页面上注册service worker,所以我们知道浏览器接收的service worker没有在网络种没有被篡改。

Github Pages是由HTTPS提供服务的,所以是一个绝佳的展示demo的地方。

初始生命周期

当你调用.register之后,你的service worker会经历三个阶段

  1. Download
  2. Install
  3. Activate

你可以使用事件和install以及activate进行交互:

self.addEventListener('install', function(event) {
  event.waitUntil(
    fetchStuffAndInitDatabases()
  );
});

self.addEventListener('activate', function(event) {
  // You're good to go!
});

你可以向event.waitUntill传递一个promise从而来继承这个过程。一旦activate事件被触发了,你的service worker就可以控制页面了!

那么我现在可以控制页面了?

额,不完全是。当document浏览时,它会选择一个service worker作为它的控制器,因此你使用.register注册的document并不是被控制的,因为那并不是service worker首次加载的地方。

如果你刷新document,它将会是在service worker的控制之下。你可以通过navigator.serviceWorker.controller来看一下是哪个service worker在进行控制,如果没有的话结果就会是null

注意:当你从一个service worker更新到另外一个的时候,可能会有一点点不一点。我们会进入“Updating”阶段。

如果使用shift来重载网页的话,加载就会有控制器了,这样做是为了测试CSS以及JS变化。

Document通常是和一个service worker存在于整个声明周期,或者根本就没有service worker。然而,service worker可以调用self.skipWaiting()(spec) 来立刻接管范围内的所有页面。

网络截获

self.addEventListener('fetch', function(event) {
  console.log(event.request);
});

你可以利用fetch事件:

  • 在你的service worker作用域下浏览
  • 任何被这些页面触发的请求,甚至是对其他源的请求

这意味着你可以监听所有对于这个页面的请求,CSS,JS,图片,XHR,图标等等所有。