原文: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:

开始

首先你需要注册一个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,图标等等所有。

  • iframes & <object>–这些将根据它们的资源URL选择其控制器
  • Service workers - 对于service worker的fetch/update请求不会通过service worker
  • 请求是在service worker之内出发的 - 否则你会获得一个循环

request对象会给你关于这个request的信息,比如它的URL,方法以及头部。但是最有趣的是,他可以劫持请求并且给出不同的响应。

self.addEventListener('fetch', function(event) {
event.respondWith(new Response("Hello world!"));
});

这是一个 demo.

.repondWith使用一个Reponse对象或者一个解析后的promise。上面我们是在创建一个手工的response。这个Reponse对象来自于 Fetch Spec.。在这个规范里面同样也存在着fetch()方法,它会返回一个promise作为响应,这意味着你可以在任何地方获取你的响应。

self.addEventListener('fetch', function(event) {
if (/\.jpg$/.test(event.request.url)) {
event.respondWith(
fetch('//www.google.co.uk/logos/…3-hp.gif', {
mode: 'no-cors'
})
);
}
});

在上面,我捕获了以.jpg结尾的请求并且将Google doodle作为响应。fetch()请求默认是 CORS,但是通过设置no-cors我可用使用这个响应,即使他不能跨域访问headers(尽管我们不能利用JavaScript访问内容)。这是demo.

Promise能够让你从一个方法返回到另外一个方法:

self.addEventListener('fetch', function(event) {
event.respondWith(
fetch(event.request).catch(function() {
return new Response("Request failed!");
})
);
});

Service worker是带有一个cache API,使得以后可以方便的存储响应以便重用。不久之后,但是第一点

更新一个service worker

Service worker的生命周期是建立在Chrome的更新模型上的:在后台尽可能多地做,不要打扰用户,当当前版本关闭的时候完成更新。

无论何时你在你的service worker作用域内浏览页面,浏览器都会在后台检查更新。如果这个脚本是字节不同的,那么它就会被认为是一个新的版本,并且被安装(注意:只有这个脚本被检查,而不是外部的importScripts)。然而,老版本的会持续对页面的控制直到所有使用它的tab都被关闭了(除非在install的过程中调用.replace())。接着这个老版本的就会被回收从而新的版本开始接管。

这样做是为了避免同时运行两个版本的service worker在不同的tab中。我们当前的策略是: “cross fingers, hope it doesn’t happen”.

注意:更新遵顼header中worker脚本的新鲜度(比如max-age),除非max-age大于24个小时,否则最多只能保持24个小时。

self.addEventListener('install', function(event) {
// this happens while the old version is still in control
event.waitUntil(
fetchStuffAndInitDatabases()
);
}); self.addEventListener('activate', function(event) {
// the old version is gone now, do what you couldn't
// do while it was still around
event.waitUntil(
schemaMigrationAndCleanup()
)
});

下面是实践中的实现

不幸的是,刷新一个tab不足够收集到旧的woker兵器让新的进行接管。浏览期在上传当前页面之前向下一个页面发送请求,所以不存在当前active worker被释放。

最简单的方法是关闭然后重新打开这个tab(cmd+w,然后cmd+shift+t Mac),或者shift+reload然后就是正常的重新加载了。

缓存

Service worker带有一个caching API能够让你产生由请求作为键值的store。

self.addEventListener('install', function(event) {
// pre cache a load of stuff:
event.waitUntil(
caches.open('myapp-static-v1').then(function(cache) {
return cache.addAll([
'/',
'/styles/all.css',
'/styles/imgs/bg.png',
'/scripts/all.js'
]);
})
)
}); self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(cachedResponse) {
return cachedResponse || fetch(event.request);
})
);
});

在缓存之内匹配类似于浏览器的缓存。方法,URL以及varyheader都被考虑在内,但是header的新鲜度被忽略了。缓存的东西只有在你手动移除的时候才生效。

你可以通过cache.put(request, response)向缓存中添加独立的条目,包括你自己产生的。你也可以控制匹配,忽略其它的,比如查询字符串,方法以及vary header。

其它service worker相关的标准

由于service worker可以及时地调动事件,及时未打开页面,也可以在后台偶尔调用其它功能:

总结

这份文档只是简要地介绍了service worker的能力,并不是售空页面或者service worker实例的所有的可用的API。也不涉及创作,修改以及更新应用程序的service worker。通过这个,希望能够引导你理解service worker中的promise以及对于URL友好的以及可伸缩的默认支持离线使用的web应用的丰富的promise。

Acknowledgments

Many thanks to Web Personality of the Year nominee Jake (“B.J.”) Archibald, David Barrett-Kahn, Anne van Kesteren, Michael Nordman, Darin Fisher, Alec Flett, Andrew Betts, Chris Wilson, Aaron Boodman, Dave Herman, Jonas Sicking, Greg Billock, Karol Klepacki, Dan Dascalescu, and Christian Liebel for their comments and contributions to this document and to the discussions that have informed it.

service worker介绍的更多相关文章

  1. 渐进式web应用开发---service worker 原理及介绍(一)

    渐进式web应用(progressive Web app) 是现代web应用的一种新形式.它利用了最新的web功能,结合了原生移动应用的独特特性与web的优点,为用户带来了新的体验. 一:传统web端 ...

  2. Service Worker

    Service Worker 随着前端快速发展,应用的性能已经变得至关重要,关于这一点大佬做了很多统计.你可以去看看. 如何降低一个页面的网络请求成本从而缩短页面加载资源的时间并降低用户可感知的延时是 ...

  3. JavaScript是如何工作的:Service Worker的生命周期及使用场景

    摘要: 理解Service Worker. 原文:JavaScript 是如何工作的:Service Worker 的生命周期及使用场景 作者:前端小智 Fundebug经授权转载,版权归原作者所有. ...

  4. 转《service worker在移动端H5项目的应用》

    1. PWA和Service Worker的关系 PWA (Progressive Web Apps) 不是一项技术,也不是一个框架,我们可以把她理解为一种模式,一种通过应用一些技术将 Web App ...

  5. 浏览器缓存和Service Worker

    浏览器缓存和Service Worker @billshooting 2018-05-06 字数 6175 Follow me on Github 标签: BOM 1. 传统的HTTP浏览器缓存策略 ...

  6. [转] service worker初探:超级拦截器与预缓存

    在2014年,W3C公布了service worker的草案,service worker提供了很多新的能力,使得web app拥有与native app相同的离线体验.消息推送体验. service ...

  7. service worker在移动端H5项目的应用

    1. PWA和Service Worker的关系 PWA (Progressive Web Apps) 不是一项技术,也不是一个框架,我们可以把她理解为一种模式,一种通过应用一些技术将 Web App ...

  8. [PWA] 9. Service worker registerion && service work's props, methods and listeners

    In some rare cases, you need to ask user to refresh the browsser to update the version. Maybe becaus ...

  9. [PWA] 2. Service worker life cycle

    Once serive worker is registered, the first time we go to the app, we cannot see the logs from servc ...

随机推荐

  1. React Native 之SectionList

    接上一篇: /pages/SectionListDemo.js import React, {Fragment,Component} from 'react'; import { SafeAreaVi ...

  2. RMI实现方案

  3. ELK整合Filebeat监控nginx日志

    ELK 日志分析 1. 为什么用到 ELK 一般我们需要进行日志分析场景:直接在日志文件中 grep. awk 就可以获得自己想要的信息.但在规模较大的场景中,此方法效率低下,面临问题包括日志量太大如 ...

  4. 【bzoj2882】工艺

    题目描述: 小敏和小燕是一对好朋友. 他们正在玩一种神奇的游戏,叫Minecraft. 他们现在要做一个由方块构成的长条工艺品.但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的 ...

  5. 小程序中css3实现优惠券

    效果如下: css3实现优惠券 知识储备 颜色渐变 linear-gradient() css伪类 :before :after index.wxss .app { /* padding: 20rpx ...

  6. spark 学习网站和资料

    spark 官网首页 https://spark.apache.org/ spark 官网文档 spark scala API 文档 https://spark.apache.org/docs/lat ...

  7. 20160513--js 弹出窗口带有iframe控件 备忘

    需要引用JQuery. /*! * 主 题:<页面弹出窗口> * 说 明:用于页面弹出的窗口. * 功能描述: * 1.生成弹出窗口,窗口内包括iframe控件: * 2.窗口弹出时,生成 ...

  8. Delphi XE2 之 FireMonkey 入门(25) - 数据绑定: TBindingsList: 表达式的灵活性及表达式函数

    Delphi XE2 之 FireMonkey 入门(25) - 数据绑定: TBindingsList: 表达式的灵活性及表达式函数 绑定表达式中可以有简单的运算和字符串连接, 但字符串需放在双引号 ...

  9. JavaScript 变量,语句

    定义变量的方式: var   变量可以没有初始值,变量可以修改,变量可以覆盖,存在变量提升. // 变量提升机制 console.log(name)// undefined var name = &q ...

  10. c# thread4——lock,死锁,以及monitor关键字

    多线程的存在是提高系统效率,挖掘cpu性能的一种手段,那么控制它,能够协同多个线程不发生bug是关键. 首先我们来看一段不安全的多线程代码. public abstract class Calcula ...