始建三个非常轻巧的离线页面www.301.net,worker完毕加速

应用瑟维斯 worker完成加快/离线访问静态blog网址

2017/02/19 · JavaScript
· Service Worker

初稿出处: Yang
Bo   

现行反革命非常的火基于Github
page和markdown的静态blog,非凡适合能力的考虑和习惯,针对分化的语言都有1些可观的静态blog系统出现,如Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于静态内容的性状非凡适合做缓存来加速页面包车型客车拜会,就选拔Service
worker
来贯彻加速,结果是除了PageSpeed,CDN那个大规模的服务器和网络加速之外,通过客户端完成了越来越好的访问体验。

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

最初的文章出处: Matt
Gaunt   译文出处:[w3ctech

  • 10年踪迹]()   

原生App具备Web应用普通所不具备的富离线体验,定期的敦默寡言更新,音信文告推送等功能。而新的Serviceworkers标准让在Web App上独具那个效能成为恐怕。

采取 Service worker 制造2个极度轻便的离线页面

2016/06/07 · JavaScript
· 1 评论 · Service
Worker

本文由 伯乐在线 –
刘健超-J.c
翻译,艾凌风
校稿。未经许可,禁止转发!
英文出处:Dean
Hume。欢迎到场翻译组。

让大家想像以下景况:我们那时候在一辆通往农村的列车上,用运动装备瞧着壹篇很棒的稿子。与此同时,当你点击“查看越多”的链接时,轻轨忽然进入了隧道,导致移动设备失去了网络,而
web 页面会展现出类似以下的始末:

www.301.net 1

那是极度令人悲伤的心得!幸运的是,web
开辟者们能经过1些新性情来创新那类的用户体验。笔者近年来间接在折腾 ServiceWorkers,它给 web 带来的点不清或者性总能给本身欣喜。Service Workers
的完美国特务工作人士人士质之1是同意你检查实验网络请求的面貌,并让你作出相应的响应。

在那篇文章里,作者打算用此本性检查用户的当前网络连接意况,要是没连接则赶回3个最棒轻易的离线页面。尽管那是二个万分基础的案例,但它能给您带来启发,让你精晓运营并运维该天性是何等的回顾!假设您没通晓过
Service Worker,小编提议你看看此 Github
repo,理解越来越多相关的新闻。

在该案例开端前,让大家先轻巧地看看它的干活流程:

  1. 在用户第一次访问大家的页面时,大家会设置 ServiceWorker,并向浏览器的缓存增添大家的离线 HTML 页面
  2. 然后,要是用户打算导航到另三个 web
    页面(同叁个网址下),但此时已断网,那么大家将重回已被缓存的离线
    HTML 页面
  3. 可是,若是用户打算导航到此外三个 web
    页面,而那时候网络已连接,则能照常浏览页面

加快/离线访问只需三步

  • 首页加多注册代码

JavaScript

<script> if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/sw.js’); } </script>

1
2
3
4
5
<script>
if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/sw.js’);
}
</script>
  • 复制代码

将保存到您的网址根目录下

  • 修改不缓存域名列表及离线状态页面

在你的sw.js中修改

JavaScript

const ignoreFetch = [ /https?:\/\/cdn.bootcss.com\//,
/https?:\/\/static.duoshuo.com\//,
/https?:\/\/www.google-analytics.com\//,
/https?:\/\/dn-lbstatics.qbox.me\//, ];

1
2
3
4
5
6
const ignoreFetch = [
  /https?:\/\/cdn.bootcss.com\//,
  /https?:\/\/static.duoshuo.com\//,
  /https?:\/\/www.google-analytics.com\//,
  /https?:\/\/dn-lbstatics.qbox.me\//,
];

打开Chrome Dev Tools->Source,看看本身的blog都引用了怎么着第一方财富,各种加到忽略列表里。

www.301.net 2

在根目录下增多offline.html,在并未有网络且缓存中也尚无时采纳,效果如下:

www.301.net 3

在根目录下加多offline.svg,在无互连网时图片能源请求重返该文件。

Service Worker 是什么?

2个 service worker
是壹段运营在浏览器后台进度里的台本,它独立于当下页面,提供了那个不供给与web页面交互的法力在网页背后悄悄施行的力量。在今后,基于它能够完结消息推送,静默更新以及地理围栏等劳动,可是近年来它首先要具备的功能是挡住和处理互联网请求,包括可编制程序的响应缓存管理。

缘何说那一个API是2个分外棒的API呢?因为它使得开垦者能够支撑越来越好的离线体验,它赋予开荒者完全调控离线数据的力量。

在service worker提议在此之前,此外3个提供开荒者离线体验的API叫做App
Cache。可是App
Cache有个别局限性,例如它能够很轻易地化解单页应用的标题,可是在多页应用上会很麻烦,而Serviceworkers的面世便是为了化解App Cache的痛点。

上面详细说一下service worker有哪些需求留意的地方:

  • 它是JavaScript
    Worker,所以它无法一向操作DOM。但是service
    worker能够透过postMessage与页面之间通讯,把音信通告给页面,若是需求的话,让页面本人去操作DOM。
  • Serviceworker是三个可编制程序的网络代理,允许开拓者调控页面上处理的网络请求。
  • 在不被运用的时候,它会友善终止,而当它再也被用到的时候,会被再一次激活,所以您无法注重于service
    worker的onfecth和onmessage的处理函数中的全局状态。假若您想要保存一些持久化的消息,你能够在service
    worker里使用IndexedDB API。
  • Serviceworker多量使用promise,所以倘使您不精晓什么是promise,那你须求先读书这篇文章。

让大家初叶吧

倘诺你有以下 HTML 页面。那即使那些基础,但能给您完整思路。

XHTML

<!DOCTYPE html>

1
<!DOCTYPE html>

进而,让大家在页面里登记 Service Worker,那里仅创造了该对象。向正要的
HTML 里加多以下代码。

JavaScript

<script> // Register the service worker // 注册 service worker if
(‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/service-worker.js’).then(function(registration)
{ // Registration was successful // 注册成功 console.log(‘ServiceWorker
registration successful with scope: ‘, registration.scope);
}).catch(function(err) { // registration failed 🙁 // 注册退步 🙁
console.log(‘瑟维斯Worker registration failed: ‘, err); }); }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
// Register the service worker
// 注册 service worker
if (‘serviceWorker’ in navigator) {
    navigator.serviceWorker.register(‘/service-worker.js’).then(function(registration) {
    // Registration was successful
    // 注册成功
    console.log(‘ServiceWorker registration successful with scope: ‘, registration.scope);
}).catch(function(err) {
    // registration failed 🙁
    // 注册失败 🙁
    console.log(‘ServiceWorker registration failed: ‘, err);
   });
}
</script>

下一场,大家须要创设 Service Worker 文件并将其命名称叫‘service-worker.js‘。大家打算用那一个 Service Worker
拦截任何互连网请求,以此检查互连网的连接性,并依照检查结果向用户再次来到最适合的剧情。

JavaScript

‘use strict’; var cacheVersion = 1; var currentCache = { offline:
‘offline-cache’ + cacheVersion }; const offlineUrl =
‘offline-page.html’; this.addEventListener(‘install’, event => {
event.waitUntil( caches.open(currentCache.offline).then(function(cache)
{ return cache.addAll([ ‘./img/offline.svg’, offlineUrl ]); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
‘use strict’;
 
var cacheVersion = 1;
var currentCache = {
  offline: ‘offline-cache’ + cacheVersion
};
const offlineUrl = ‘offline-page.html’;
 
this.addEventListener(‘install’, event => {
  event.waitUntil(
    caches.open(currentCache.offline).then(function(cache) {
      return cache.addAll([
          ‘./img/offline.svg’,
          offlineUrl
      ]);
    })
  );
});

在上边的代码中,我们在安装 瑟维斯 Worker
时,向缓存增加了离线页面。固然大家将代码分为几小块,可看到前几行代码中,作者为离线页面钦赐了缓存版本和U奇骏L。假若您的缓存有两样版本,那么你只需立异版本号就可以轻便地清除缓存。在大约在第3二行代码,笔者向那一个离线页面及其财富(如:图片)发出请求。在收获成功的响应后,大家将离线页面和相关能源丰裕到缓存。

未来,离线页面已存进缓存了,我们可在急需的时等候检查索它。在同一个 ServiceWorker 中,大家供给对无网络时回来的离线页面增加相应的逻辑代码。

JavaScript

this.add伊芙ntListener(‘fetch’, event => { // request.mode = navigate
isn’t supported in all browsers // request.mode = naivgate
并不曾赢得全部浏览器的支撑 // so include a check for Accept: text/html
header. // 因而对 header 的 Accept:text/html 实行核实 if
(event.request.mode === ‘navigate’ || (event.request.method === ‘GET’ &&
event.request.headers.get(‘accept’).includes(‘text/html’))) {
event.respondWith( fetch(event.request.url).catch(error => { //
Return the offline page // 再次来到离线页面 return caches.match(offlineUrl);
}) ); } else{ // Respond with everything else if we can //
再次回到任何我们能回来的东西 event.respondWith(caches.match(event.request)
.then(function (response) { return response || fetch(event.request); })
); } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
this.addEventListener(‘fetch’, event => {
  // request.mode = navigate isn’t supported in all browsers
  // request.mode = naivgate 并没有得到所有浏览器的支持
  // so include a check for Accept: text/html header.
  // 因此对 header 的 Accept:text/html 进行核实
  if (event.request.mode === ‘navigate’ || (event.request.method === ‘GET’ && event.request.headers.get(‘accept’).includes(‘text/html’))) {
        event.respondWith(
          fetch(event.request.url).catch(error => {
              // Return the offline page
              // 返回离线页面
              return caches.match(offlineUrl);
          })
    );
  }
  else{
        // Respond with everything else if we can
        // 返回任何我们能返回的东西
        event.respondWith(caches.match(event.request)
                        .then(function (response) {
                        return response || fetch(event.request);
                    })
            );
      }
});

为了测试该功能,你能够采纳 Chrome
内置的开采者工具。首先,导航到你的页面,然后若是设置上了 ServiceWorker,就张开 Network 标签并将节流(throttling)改为
Offline。(译者注:若将节流设置为 Offline
没意义,则可由此关闭互联网或然通过360资阳警卫禁止 Chrome 访问网络)

www.301.net 4

假定你刷新页面,你应当能收占星应的离线页面!

www.301.net 5

比方你只想大概地质衡量试该意义而不想写任何代码,那么你能够访问小编已开立好的
demo。此外,上述总体代码能够在
Github repo 找到。

自作者领悟用在此案例中的页面很轻松,但您的离线页面则在于你协调!要是你想深切该案例的始末,你可感到离线页面增多缓存破坏(
cache busting),如:
此案例。

加快效果

首页加速后,互联网请求从1陆降为一,加载时间从2.2玖陆s降为0.654s,获得了须臾间加载的结果。

www.301.net 6

基于webpagetest

查看测试结果

瑟维斯 Worker的生命周期

Service worker具有二个全然独立于Web页面包车型大巴生命周期。

要让一个service
worker在你的网址上生效,你要求先在您的网页中注册它。注册一个service
worker之后,浏览器会在后台默默运维一个service worker的装置进程。

在安装进度中,浏览器会加载并缓存一些静态财富。假如具备的公文被缓存成功,service
worker就安装成功了。倘若有别的公文加载或缓存失利,那么安装进度就会退步,service
worker就不能够被激活(也即没能安装成功)。假使产生如此的主题材料,别顾忌,它会在下次再尝试安装。

当安装到位后,service
worker的下一步是激活,在这一品级,你还是能够升高3个service
worker的本子,具体内容大家会在前边讲到。

在激活之后,service
worker将接管全体在协调管辖域范围内的页面,然而要是三个页面是刚刚注册了service
worker,那么它那三次不会被接管,到下三次加载页面的时候,service
worker才会生效。

当service
worker接管了页面之后,它只怕有两种情景:要么被停止以节省外部存款和储蓄器,要么会处理fetch和message事件,这五个事件分别发出于1个网络请求出现照旧页面上发送了多少个音讯。

下图是二个简化了的service worker初次安装的生命周期:

www.301.net 7

展开阅读

其余,还有多少个很棒的离线成效案例。如:Guardian 营造了一个独具 crossword
puzzle(填字游戏)的离线
web 页面 –
由此,纵然等待网络重连时(即已在离线状态下),也能找到一点乐趣。作者也援引看看
Google Chrome Github
repo,它含有了许多例外的
Service Worker 案例 – 当中有的利用案例也在那!

可是,假如你想跳过上述代码,只是想大致地经过3个库来拍卖相关操作,那么本身引入您看看
UpUp。那是一个轻量的剧本,能让您更自在地行使离线成效。

打赏援救自个儿翻译越来越多好小说,感谢!

打赏译者

加速/离线原理探究

在大家伊始写码从前

从这个体系地址拿到chaches
polyfill。

这个polyfill支持CacheStorate.match,Cache.add和Cache.addAll,而现在Chrome
M40实现的Cache
API还不曾帮衬这几个主意。

将dist/serviceworker-cache-polyfill.js放到你的网址中,在service
worker中经过importScripts加载进来。被service
worker加载的剧本文件会被自动缓存。

JavaScript

importScripts(‘serviceworker-cache-polyfill.js’);

1
importScripts(‘serviceworker-cache-polyfill.js’);

需要HTTPS

在开辟阶段,你能够通过localhost使用service
worker,可是若是上线,就供给您的server支持HTTPS。

您能够因此service
worker威胁连接,伪造和过滤响应,非凡逆天。就算你能够约束自个儿不干坏事,也会有人想干坏事。所认为了防止旁人使坏,你不得不在HTTPS的网页上注册service
workers,那样我们能力够幸免加载service
worker的时候不被歹徒篡改。(因为service
worker权限不小,所以要防卫它本人被坏蛋篡改利用——译者注)

Github
Pages见怪不怪是HTTPS的,所以它是一个上佳的原状实验田。

假定您想要让你的server协理HTTPS,你必要为您的server获得2个TLS证书。分化的server安装方法差异,阅读支持文书档案并透过Mozilla’s
SSL config
generator打听最好施行。

打赏扶助本人翻译越多好文章,多谢!

任选1种支付办法

www.301.net 8
www.301.net 9

1 赞 3 收藏 1
评论

什么是 Service worker

www.301.net 10

如上图,Service
worker

是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当二个页面注册了三个
Service
worker
,它就足以挂号一层层事件处理器来响应如互联网请求和音讯推送这个事件。Service
worker

能够被用来管理缓存,当响应1个互连网请求时方可布置为回到缓存依旧从网络获得。由于Service
worker

是依照事件的,所以它只在拍卖那么些事件的时候被调入内存,不用想念常驻内部存储器占用能源导致系统变慢。

使用Service Worker

当今我们有了polyfill,并且消除了HTTPS,让我们看看到底怎么用service
worker。

至于笔者:刘健超-J.c

www.301.net 11

前端,在路上…
个人主页 ·
我的稿子 ·
19 ·
    

www.301.net 12

瑟维斯 worker生命周期

www.301.net 13

Service
worker

为网页增加2个接近于APP的生命周期,它只会响应系统事件,就算浏览器关闭时操作系统也足以唤起Service
worker
,这一点卓殊重要,让web
app与native app的力量变得就好像了。

Service
worker
在Register时会触发Install事件,在Install时方可用来预先获取和缓存应用所需的能源并设置各样文件的缓存战术。

一旦Service
worker
处于activated状态,就足以完全调节应用的财富,对网络请求实行检讨,修改互联网请求,从互联网上赢得并重临内容恐怕重临由已安装的Service
worker
预示获取并缓存好的能源,甚至还足以扭转内容并再次回到给网络语法。

富有的这个都用户都以晶莹的,事实上,多个安插优良的Service
worker
就好像二个智能缓存系统,抓牢了互联网和缓存作用,选用最优办法来响应互连网请求,让动用越发安宁的运行,即便未有互连网也没提到,因为你能够完全调节互联网响应。

怎么注册和装置service worker

要安装service
worker,你须要在您的页面上注册它。这一个手续告诉浏览器你的service
worker脚本在何地。

JavaScript

if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/sw.js’).then(function(registration) {
// Registration was successful console.log(‘ServiceWorker registration
successful with scope: ‘, registration.scope); }).catch(function(err) {
// registration failed 🙁 console.log(‘ServiceWorker registration
failed: ‘, err); }); }

1
2
3
4
5
6
7
8
9
if (‘serviceWorker’ in navigator) {
  navigator.serviceWorker.register(‘/sw.js’).then(function(registration) {
    // Registration was successful
    console.log(‘ServiceWorker registration successful with scope: ‘,    registration.scope);
  }).catch(function(err) {
    // registration failed 🙁
    console.log(‘ServiceWorker registration failed: ‘, err);
  });
}

地方的代码检查service worker API是还是不是可用,假使可用,service
worker /sw.js 被注册。

如若这么些service worker已经被登记过,浏览器会自动忽略上边的代码。

有二个索要越发表明的是service
worker文件的门径,你一定注意到了在那些例子中,service
worker文件被放在这些域的根目录下,那象征service
worker和网址同源。换句话说,那么些service
work将会收到那一个域下的具有fetch事件。如果本身将service
worker文件注册为/example/sw.js,那么,service worker只能收到/example/路径下的fetch事件(例如: /example/page1/, /example/page2/)。

现行反革命你能够到 chrome://inspect/#service-workers 检查service worker是否对你的网站启用了。

www.301.net 14

当service
worker第三版被完结的时候,你也得以在chrome://serviceworker-internals中查看,它很有用,通过它可以最直观地熟悉service worker的生命周期,不过这个功能很快就会被移到chrome://inspect/#service-workers中。

您会意识那么些功功效够很有利地在一个模拟窗口中测试你的service
worker,那样您能够关闭和再一次展开它,而不会影响到您的新窗口。任何创制在模拟窗口中的注册服务和缓存在窗口被关闭时都将未有。

Service worker的操纵从第壹回页面访问开头

在第二遍加载页面时,全体能源都以从互联网载的,Service
worker

在首回加载时不会获得调整网络响应,它只会在承袭访问页面时起效率。

www.301.net 15

页面第壹回加载时做到install,并进入idle状态。

www.301.net 16

页面第一回加载时,进入activated状态,准备处理全数的事件,同时
浏览器会向服务器发送三个异步 请求来检查Service
worker
自身是否有新的版本,构成了Service
worker
的立异机制。

www.301.net 17

Service
worker
拍卖完全体的轩然大波后,进入idle状态,最后进入terminated状态财富被释放,当有新的风浪发生时再度被调用。

Service Worker的安装步骤

在页面上实现登记手续之后,让大家把注意力转到service
worker的脚本里来,在那其间,我们要旗开马到它的安装步骤。

在最中央的事例中,你要求为install事件定义八个callback,并调整哪些文件你想要缓存。

JavaScript

// The files we want to cache var urlsToCache = [ ‘/’,
‘/styles/main.css’, ‘/script/main.js’ ]; // Set the callback for the
install step self.addEventListener(‘install’, function(event) { //
Perform install steps });

1
2
3
4
5
6
7
8
9
10
11
// The files we want to cache
var urlsToCache = [
  ‘/’,
  ‘/styles/main.css’,
  ‘/script/main.js’
];
 
// Set the callback for the install step
self.addEventListener(‘install’, function(event) {
    // Perform install steps
});

在大家的install callback中,我们要求进行以下步骤:

  1. 拉开贰个缓存
  2. 缓存大家的公文
  3. 决定是否持有的财富是还是不是要被缓存

JavaScript

var CACHE_NAME = ‘my-site-cache-v1’; var urlsToCache = [ ‘/’,
‘/styles/main.css’, ‘/script/main.js’ ];
self.addEventListener(‘install’, function(event) { // Perform install
steps event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) {
console.log(‘Opened cache’); return cache.addAll(urlsToCache); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var CACHE_NAME = ‘my-site-cache-v1’;
var urlsToCache = [
  ‘/’,
  ‘/styles/main.css’,
  ‘/script/main.js’
];
 
self.addEventListener(‘install’, function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log(‘Opened cache’);
        return cache.addAll(urlsToCache);
      })
  );
});

地点的代码中,大家透过caches.open张开大家钦赐的cache文件名,然后大家调用cache.addAll并传到大家的公文数组。这是通过一体系promise(caches.open

cache.addAll)实现的。event.waitUntil获得三个promise并应用它来收获安装开支的时间以及是还是不是安装成功。

一旦全部的文书都被缓存成功了,那么service
worker就安装成功了。如若别的一个文本下载战败,那么安装步骤就会退步。那些主意允许你依靠于您本人钦赐的保有能源,但是那象征你须要相当的小心地决定哪些文件供给在安装步骤中被缓存。内定了太多的文件的话,就会扩张设置退步率。

地点只是1个轻便的例子,你能够在install事件中进行其它操作照旧甚至忽视install事件。

特点

  • 浏览器

谷歌(Google) Chrome,Firefox,Opera以及境内的各个双核浏览器都帮助,不过 safari
不援助,那么在不帮忙的浏览器里Service
worker
不工作。

  • https

网址必须启用https来担保使用Service
worker
页面包车型客车安全性,开垦时localhost暗中认可以为是平安的。

  • non-block

Service
worker

中的 Javascript 代码必须是非阻塞的,因为 localStorage
是阻塞性,所以不应有在 瑟维斯 Worker 代码中动用 localStorage。

  • 单独的实践环境

Service
worker
运转在协调的大局环境中,平常也运营在融洽独自的线程中。

  • 未有绑定到一定页面

service work能调控它所加载的全方位范围内的财富。

  • 不能够操作DOM

跟DOM所处的条件是互相隔开的。

www.301.net 18

  • 向来不浏览页面时也足以运营

收到系统事件,后台运营

  • 事件驱动,要求时运维,不要求时就告一段落

按需实施,只在须求时加载到内部存款和储蓄器

  • 可升级

实施时会异步获取最新的版本

怎么样缓存和再次回到Request

你早已设置了service worker,你现在得以回到您缓存的请求了。

当service
worker被安装成功还要用户浏览了另一个页面大概刷新了脚下的页面,service
worker将开端收受到fetch事件。上面是3个事例:

JavaScript

self.addEventListener(‘fetch’, function(event) { event.respondWith(
caches.match(event.request) .then(function(response) { // Cache hit –
return response if (response) { return response; } return
fetch(event.request); } ) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
self.addEventListener(‘fetch’, function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit – return response
        if (response) {
          return response;
        }
 
        return fetch(event.request);
      }
    )
  );
});

地点的代码里我们定义了fetch事件,在event.respondWith里,大家传入了三个由caches.match发生的promise.caches.match
查找request中被service worker缓存命中的response。

倘使大家有一个命中的response,我们重回被缓存的值,不然大家回来三个实时从网络请求fetch的结果。那是二个十三分轻巧的事例,使用具备在install步骤下被缓存的财富。

一经大家想要增量地缓存新的呼吁,大家能够通过拍卖fetch请求的response并且增进它们到缓存中来落成,例如:

JavaScript

self.addEventListener(‘fetch’, function(event) { event.respondWith(
caches.match(event.request) .then(function(response) { // Cache hit –
return response if (response) { return response; } // IMPORTANT: Clone
the request. A request is a stream and // can only be consumed once.
Since we are consuming this // once by cache and once by the browser for
fetch, we need // to clone the response var fetchRequest =
event.request.clone(); return fetch(fetchRequest).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 2 stream. var responseToCache = response.clone();
caches.open(CACHE_NAME) .then(function(cache) {
cache.put(event.request, responseToCache); }); return response; } ); })
); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
self.addEventListener(‘fetch’, function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit – return response
        if (response) {
          return response;
        }
 
        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();
 
        return fetch(fetchRequest).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 2 stream.
            var responseToCache = response.clone();
 
            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });
 
            return response;
          }
        );
      })
    );
});

代码里大家所做事情包罗:

  1. 增进一个callback到fetch请求的 .then 方法中
  2. 假定大家赢得了多个response,大家进行如下的反省:
    1. 有限支撑response是一蹴而就的
    2. 自笔者批评response的动静是或不是是200
    3. 管教response的项目是basic,那表示请求笔者是同源的,非同源(即跨域)的乞求也无法被缓存。
  3. 假使大家经过了检查,clone本条请求。这么做的来由是假设response是一个Stream,那么它的body只能被读取1遍,所以我们得将它克隆出来,壹份发给浏览器,壹份发给缓存。

实现加速/离线

怎么着立异2个Service Worker

您的service
worker总有需求更新的那壹天。当那一天来临的时候,你必要依照如下步骤来更新:

  1. 立异您的service worker的JavaScript文件
    1. 当用户浏览你的网址,浏览器尝试在后台下载service
      worker的剧本文件。只要服务器上的文书和地面文件有一个字节分歧,它们就被判别为索要更新。
  2. 立异后的service worker将上马运转,install event被另行触发。
  3. 在这一个时刻节点上,当前页面生效的如故是老版本的service
    worker,新的servicer worker将进入”waiting”状态。
  4. 近年来页面被关门之后,老的service worker进度被杀死,新的servicer
    worker正式生效。
  5. 要是新的service worker生效,它的activate事件被触发。

代码更新后,平常必要在activate的callback中举行三个管制cache的操作。因为您会必要消除掉此前旧的数目。大家在activate而不是install的时候实践这几个操作是因为壹旦大家在install的时候立即实践它,那么还是在运作的旧版本的多少就坏了。

事先大家只使用了2个缓存,叫做my-site-cache-v1,其实我们也可以使用多个缓存的,例如一个给页面使用,一个给blog的内容提交使用。这意味着,在install步骤里,我们可以创建两个缓存,pages-cache-v1和blog-posts-cache-v1,在activite步骤里,我们可以删除旧的my-site-cache-v1。

下边包车型客车代码能够循环全体的缓存,删除掉全数不在白名单中的缓存。

JavaScript

self.addEventListener(‘activate’, function(event) { var cacheWhitelist =
[‘pages-cache-v1’, ‘blog-posts-cache-v1’]; event.waitUntil(
caches.keys().then(function(cacheNames) { return Promise.all(
cacheNames.map(function(cacheName) { if
(cacheWhitelist.indexOf(cacheName) === -1) { return
caches.delete(cacheName); } }) ); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.addEventListener(‘activate’, function(event) {
 
  var cacheWhitelist = [‘pages-cache-v1’, ‘blog-posts-cache-v1’];
 
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Cache

网页缓存有成百上千,如HTTP缓存,localStorage,sessionStorage和cacheStorage都足以灵活搭配实行缓存,但操作太繁琐,直接使用越来越高等Service
worker

–本文的主人公。

拍卖边界和填坑

这壹节内容相比较新,有多数待定细节。希望那①节非常的慢就不需求讲了(因为标准会处理这一个题目——译者注),可是未来,这么些剧情依然应当被提一下。

添加Service worker入口

在web app的首页加多以下代码

JavaScript

<script> if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/sw.js’); } </script>

1
2
3
4
5
<script>
if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/sw.js’);
}
</script>

1经浏览器协助serviceWorker就报了名它,不援救依然健康浏览,没有Service
worker
所提供的升高成效。

Service worker调控范围:
简易情形下,将sw.js坐落网址的根目录下,那样Service
worker
能够调整网址有着的页面,,同理,借使把sw.js放在/my-app/sw.js那正是说它不得不调节my-app目录下的页面。
sw.js放在/js/目录呢?越来越好的目录结构和界定调节呢?
在登记时钦命js地方并安装限制。

JavaScript

navigator.serviceWorker.register(‘/js/sw.js’, {scope:
‘/sw-test/’}).then(function(registration) { // Registration was
successful console.log(‘ServiceWorker registration successful with
scope: ‘, registration.scope); }).catch(function(err) { // registration
failed 🙁 console.log(‘ServiceWorker registration failed: ‘, err); });

1
2
3
4
5
6
7
navigator.serviceWorker.register(‘/js/sw.js’, {scope: ‘/sw-test/’}).then(function(registration) {
      // Registration was successful
      console.log(‘ServiceWorker registration successful with scope: ‘, registration.scope);
    }).catch(function(err) {
      // registration failed 🙁
      console.log(‘ServiceWorker registration failed: ‘, err);
    });

设若设置失利了,未有很优雅的格局获得通报

假定三个worker被登记了,不过未有出现在chrome://inspect/#service-workers或chrome://serviceworker-internals,那么很可能因为异常而安装失败了,或者是产生了一个被拒绝的的promise给event.waitUtil。

要解决那类难点,首先到 chrome://serviceworker-internals检查。打开开发者工具窗口准备调试,然后在你的install event代码中添加debugger;语句。这样,通过断点调试你更容易找到问题。

Service worker实现

监听四个事件:

JavaScript

self.addEventListener(‘install’, onInstall);
self.addEventListener(‘fetch’, onFetch);
self.addEventListener(“activate”, onActivate);

1
2
3
self.addEventListener(‘install’, onInstall);
self.addEventListener(‘fetch’, onFetch);
self.addEventListener("activate", onActivate);

fetch()最近仅帮忙Service Workers

fetch立刻补助在页面上应用了,可是当前的Chrome达成,它还只帮忙service
worker。cache
API也将在要页面上被协理,不过近来结束,cache也还不得不在service
worker中用。

install

www.301.net,JavaScript

////////// // Install ////////// function onInstall(event) {
log(‘install event in progress.’); event.waitUntil(updateStaticCache());
} function updateStaticCache() { return caches
.open(cacheKey(‘offline’)) .then((cache) => { return
cache.addAll(offlineResources); }) .then(() => { log(‘installation
complete!’); }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//////////
// Install
//////////
function onInstall(event) {
  log(‘install event in progress.’);
  event.waitUntil(updateStaticCache());
}
function updateStaticCache() {
  return caches
    .open(cacheKey(‘offline’))
    .then((cache) => {
      return cache.addAll(offlineResources);
    })
    .then(() => {
      log(‘installation complete!’);
    });
}

install时将有所符合缓存战略的财富开展缓存。

fetch()的暗中认可参数

当您选择fetch,缺省地,请求不会带上cookies等证据,要想带上的话,供给:

JavaScript

fetch(url, { credentials: ‘include’ })

1
2
3
fetch(url, {
  credentials: ‘include’
})

诸如此类设计是有理由的,它比XHRAV四的在同源下私下认可发送凭据,但跨域时扬弃凭据的规则要来得好。fetch的行为更像别的的CO普拉多S请求,例如<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

fetch

JavaScript

//////// // Fetch //////// function onFetch(event) { const request =
event.request; if (shouldAlwaysFetch(request)) {
event.respondWith(networkedOrOffline(request)); return; } if
(shouldFetchAndCache(request)) {
event.respondWith(networkedOrCached(request)); return; }
event.respondWith(cachedOrNetworked(request)); }
onFetch做为浏览器互联网请求的代办,依据需求回到网络或缓存内容,假诺得到了互联网内容,再次来到网络请求时同时进行缓存操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
////////
// Fetch
////////
function onFetch(event) {
  const request = event.request;
  if (shouldAlwaysFetch(request)) {
    event.respondWith(networkedOrOffline(request));
    return;
  }
  if (shouldFetchAndCache(request)) {
    event.respondWith(networkedOrCached(request));
    return;
  }
  event.respondWith(cachedOrNetworked(request));
}
onFetch做为浏览器网络请求的代理,根据需要返回网络或缓存内容,如果获取了网络内容,返回网络请求时同时进行缓存操作。

Non-CO卡宴S私下认可不扶助

暗许处境下,从第一方U宝马X三L跨域得到1个能源将会停业,除非对方帮助了CO帕杰罗S。你能够加上3个non-COEnclaveS选项到Request去制止战败。代价是那般做会再次来到二个“不透明”的response,意味着你不可能摸清那么些请求毕竟是旗开马到了只怕失败了。

JavaScript

cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) { return new
Request(urlToPrefetch, { mode: ‘no-cors’ }); })).then(function() {
console.log(‘All resources have been fetched and cached.’); });

1
2
3
4
5
cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {
  return new Request(urlToPrefetch, { mode: ‘no-cors’ });
})).then(function() {
  console.log(‘All resources have been fetched and cached.’);
});

activate

JavaScript

/////////// // Activate /////////// function onActivate(event) {
log(‘activate event in progress.’); event.waitUntil(removeOldCache()); }
function removeOldCache() { return caches .keys() .then((keys) => {
return Promise.all( // We return a promise that settles when all
outdated caches are deleted. keys .filter((key) => { return
!key.startsWith(version); // Filter by keys that don’t start with the
latest version prefix. }) .map((key) => { return caches.delete(key);
// Return a promise that’s fulfilled when each outdated cache is
deleted. }) ); }) .then(() => { log(‘removeOldCache completed.’); });
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
///////////
// Activate
///////////
function onActivate(event) {
  log(‘activate event in progress.’);
  event.waitUntil(removeOldCache());
}
function removeOldCache() {
  return caches
    .keys()
    .then((keys) => {
      return Promise.all( // We return a promise that settles when all outdated caches are deleted.
        keys
         .filter((key) => {
           return !key.startsWith(version); // Filter by keys that don’t start with the latest version prefix.
         })
         .map((key) => {
           return caches.delete(key); // Return a promise that’s fulfilled when each outdated cache is deleted.
         })
      );
    })
    .then(() => {
      log(‘removeOldCache completed.’);
    });
}

在activate时依照version值来删除过期的缓存。

fetch()不坚守30x重定向规范

噩运,重定向在fetch()中不会被触发,那是现阶段版本的bug;

管理 Service worker

拍卖响应式图片

img的srcset属性只怕<picture>标签会根据情况从浏览器或者网络上选择最合适尺寸的图片。

在service worker中,你想要在install步骤缓存二个图片,你有以下三种采取:

  1. 设置具有的<picture>元素或者将被请求的srcset属性。
  2. 设置单一的low-res版本图片
  3. 设置单一的high-res版本图片

相比好的方案是贰或叁,因为假设把具备的图片都给下载下来存着有点浪费内存。

假使你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互连网上下载high-res的本子,不过固然high-res版本下载失败以来,就还是用low-res版本。那个想法很好也值得去做,不过有三个主题材料:

若是大家有下面二种图片:

Screen Density Width Height
1x 400 400
2x 800 800

HTML代码如下:

JavaScript

<img src=”image-src.png” srcset=”image-src.png 1x, image-2x.png 2x”
/>

1
<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" />

只要大家在一个2x的来得模式下,浏览器会下载image-2x.png,假若大家离线,你能够读取以前缓存并再次回到image-src.png代替,假如此前它曾经被缓存过。固然如此,由现今日的格局是二x,浏览器会把400X400的图片体现存200X200,要幸免那么些主题素材将要要图片的样式上安装宽高。

JavaScript

<img src=”image-src.png” srcset=”image-src.png 1x, image-2x.png 2x”
style=”width:400px; height: 400px;” />

1
2
<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x"
style="width:400px; height: 400px;" />

www.301.net 19

<picture>标签情况更复杂一些,难度取决于你是如何创建和使用的,但是可以通过与srcset类似的思路去解决。

特定网址

  1. Google Chrome

Developer Tools->Application->Service Workers

www.301.net 20

在那边还有八个十二分实惠的复选框:

  • Offline

模仿断网状态

  • Update on reload
    加载时更新
  • Bypass for network
    总是接纳互联网内容
  1. Firefox

除非在Settings里有三个足以在HTTP环境中接纳Service
worker
的选项,适应于调节和测试,未有单独网址下的Service
worker
管理。

www.301.net 21

  1. Opera及此外双核浏览器同谷歌 Chrome
    比方看到四个一样范围内的三个Service
    worker
    ,说明Service
    woker
    更新后,而原有Service
    worker
    还并未有被terminated。

改变URL Hash的Bug

在M40版本中设有一个bug,它会让页面在更动hash的时候变成service
worker甘休工作。

你能够在此间找到更加多相关的消息: 

浏览器全局

看望您的浏览器里都有何样Service worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

能够观看曾经有贰陆个Serviceworker了,在那里能够手动Start让它工作,也得以Unregister卸载掉。

www.301.net 22

  1. Firefox

有三种方法进入Service
worker
管住分界面来手动Start或unregister。

  • 菜单栏,Tool->Web Developer->Service workers
  • 地点栏中输入

JavaScript

about:debugging#workers

1
about:debugging#workers

www.301.net 23

  1. Opera及别的双核浏览器同谷歌 Chrome

越多内容

这里有部分唇齿相依的文书档案可以参照:

更多

TODO:

  • Service
    workers
    的创新须要手动编辑version,每一回发表新小说时索要编写制定。
  • 使用AMP让页面渲染速度高达最高。

赚取帮助

即便您遇见麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家立马跟进和尽也许帮忙你化解难题。

赞 2 收藏
评论

www.301.net 12

Ref links

Service Worker Cookbook

Is service worker
ready?

Chrome service worker status
page

Firefox service worker status
page

MS Edge service worker status
page

WebKit service worker status
page

1 赞 2 收藏
评论

www.301.net 12

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注