【亚洲必赢官网】拔取serviceworker的离线访问格局,创造一个非凡简单的离线页面

迈向PWA!利用serviceworker的离线访问格局

2017/02/08 · JavaScript
· PWA

本文作者: 伯乐在线 –
pangjian
。未经小编许可,禁止转发!
迎接参与伯乐在线 专辑小编。

微信小程序来了,可以利用WEB技术在微信打造一个享有Native应用体验的拔取,业界相当看好那种样式。可是你们或许不了解,谷歌早已有近似的规划,甚至层次更高。那就是PWA(渐进式增强WEB应用)。
PWA有以下三种特色:

  • Installablity(可安装性)
  • App Shell
  • Offline(离线能力)
  • Re-engageable(推送公告能力)

不无那几个特点都是“优雅降级、渐进增强的”,给接济的装备更好的感受,不襄助的设施也不会更差。那就和微信小程序那种不佳设计的根本不一致之处。

本博客也在向着PWA的趋势迈进,第一步我拔取了Offline,也就是离线能力。可以让客户在尚未网络连接的时候仍是可以拔取部分服务。这一个能力使用了ServiceWorker技术。

落到实处思路就是,利用service
worker,另起一个线程,用来监听所有网络请求,讲曾经呼吁过的多少放入cache,在断网的景色下,间接取用cache里面的资源。为呼吁过的页面和图片,体现一个默许值。当有网络的时候,再重复从服务器更新。
亚洲必赢官网 1
代码那里就不贴了,未来或者会更加写一篇来详细介绍ServiceWorker,有趣味的能够直接参考源码。
登记起来也要命有益

JavaScript

// ServiceWorker_js (function() { ‘use strict’;
navigator.serviceWorker.register(‘/sw.js’, {scope:
‘/’}).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
10
11
12
// ServiceWorker_js
(function() {
    ‘use strict’;
    navigator.serviceWorker.register(‘/sw.js’, {scope: ‘/’}).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);
    });
 
})();

此间须要注意的是,sw.js所在的目录要当先它的支配范围,也就是scope。我把sw.js位于了根目录来决定总体目录。

接下去看看大家的末尾效果呢,你也足以在大团结的浏览器下断网尝试一下。当然有一对浏览器如今还不支持,比如盛名的Safari。

行使 Service(Service) worker 创制一个卓殊简单的离线页面

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

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

让我们想像以下场景:我们这时候在一辆通往农村的高铁上,用运动装备瞅着一篇很棒的文章。与此同时,当你点击“查看更加多”的链接时,高铁忽然进入了隧道,导致运动装备失去了网络,而
web 页面会展现出类似以下的内容:

亚洲必赢官网 2

那是非常令人心寒的体会!幸运的是,web
开发者们能由此一些新特色来创新那类的用户体验。我多年来直接在折腾 ServiceWorkers,它给 web 带来的无尽可能性总能给自己惊喜。瑟维斯(Service)(Service) Workers
的理想特质之一是允许你检测网络请求的场景,并让您作出相应的响应。

在那篇小说里,我打算用此特性检查用户的方今网络连接情况,要是没连接则赶回一个特级简单的离线页面。固然那是一个那一个基础的案例,但它能给您带来启迪,让您知道启动并运行该特性是何等的大致!假如您没精通过
Service(Service) Worker,我指出您看看此 Github
repo,了然越多相关的音讯。

在此案例发轫前,让咱们先简单地看望它的工作流程:

  1. 在用户第一次访问我们的页面时,大家会设置 ServiceWorker,并向浏览器的缓存添加大家的离线 HTML 页面
  2. 接下来,假如用户打算导航到另一个 web
    页面(同一个网站下),但这时已断网,那么我们将回到已被缓存的离线
    HTML 页面
  3. 但是,假设用户打算导航到其余一个 web
    页面,而这时网络已一而再,则能照常浏览页面

利用Service worker完结加速/离线访问静态blog网站

2017/02/19 · JavaScript
· Service Worker

初稿出处: Yang
Bo   

现今很流行基于Github
page和markdown的静态blog,万分适合技术的盘算和习惯,针对分歧的言语都有部分优秀的静态blog系统出现,如Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于静态内容的特性非常适合做缓存来增速页面的拜会,就利用【亚洲必赢官网】拔取serviceworker的离线访问格局,创造一个非凡简单的离线页面。Service
worker
来兑现加快,结果是除了PageSpeed,CDN那几个常见的服务器和网络增加速度之外,通过客户端落成了更好的造访体验。

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

原稿出处: Matt
Gaunt   译文出处:[w3ctech

  • 十年踪迹]()   

原生App拥有Web应用普通所不享有的富离线体验,定时的默不做声更新,音信通告推送等功用。而新的瑟维斯(Service)workers标准让在Web App上拥有那些成效成为可能。

离线有缓存情状

亚洲必赢官网 3

让我们开首吧

假定你有以下 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(‘瑟维斯(Service)(Service)Worker
registration successful with scope: ‘, registration.scope);
}).catch(function(err) { // registration failed 🙁 // 注册失利 🙁
console.log(‘Service(Service)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)(Service) Worker 文件并将其取名为
‘service-worker.js‘。大家打算用那么些 瑟维斯(Service)(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
      ]);
    })
  );
});

在上边的代码中,大家在装置 瑟维斯(Service)(Service) Worker
时,向缓存添加了离线页面。倘若我们将代码分为几小块,可知到前几行代码中,我为离线页面指定了缓存版本和URL。如若你的缓存有例外版本,那么您只需革新版本号即可容易地消除缓存。在大概在第
12
行代码,我向那一个离线页面及其资源(如:图片)发出请求。在得到成功的响应后,大家将离线页面和有关资源充足到缓存。

当今,离线页面已存进缓存了,大家可在急需的时候检索它。在同一个 Service(Service)Worker 中,大家需求对无网络时再次来到的离线页面添加相应的逻辑代码。

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
内置的开发者工具。首先,导航到您的页面,然后一旦设置上了 瑟维斯Worker,就开辟 Network 标签并将节流(throttling)改为
Offline。(译者注:若将节流设置为 Offline
没效果,则可通过关闭网络或者经过360康宁警卫禁止 Chrome 访问网络)

亚洲必赢官网 4

只要你刷新页面,你应该能收算命应的离线页面!

亚洲必赢官网 5

即使您只想大约地测试该效能而不想写任何代码,那么您可以访问我已开立好的
demo。其它,上述任何代码能够在
Github repo 找到。

自身知道用在此案例中的页面很简单,但你的离线页面则取决于你自己!如果您想长远该案例的始末,你可以为离线页面添加缓存破坏(
cache busting),如:
此案例。

加速/离线访问只需三步

  • 首页添加注册代码

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都引用了什么第三方资源,逐个加到忽略列表里。

亚洲必赢官网 6

在根目录下添加offline.html,在尚未网络且缓存中也从没时选用,效果如下:

亚洲必赢官网 7

在根目录下添加offline.svg,在无网络时图片资源请求再次回到该文件。

Service Worker 是什么?

一个 service worker
是一段运行在浏览器后台进度里的本子,它独自于如今页面,提供了那个不必要与web页面交互的成效在网页背后悄悄执行的力量。在未来,基于它可以落成消息推送,静默更新以及地理围栏等服务,可是近来它首先要负有的职能是阻止和处理网络请求,包罗可编程的响应缓存管理。

干什么说这几个API是一个尤其棒的API呢?因为它使得开发者可以支撑更加好的离线体验,它赋予开发者完全控制离线数据的能力。

在service worker提出从前,别的一个提供开发者离线体验的API叫做App
Cache。但是App
Cache有些局限性,例如它可以很简单地缓解单页应用的题材,但是在多页应用上会很麻烦,而Service(Service)workers的产出正是为了化解App Cache的痛点。

下边详细说一下service worker有如何需求留意的地方:

  • 它是JavaScript
    Worker,所以它不能够一贯操作DOM。然则service
    worker可以由此postMessage与页面之间通讯,把音信文告给页面,如果要求的话,让页面自己去操作DOM。
  • Serviceworker是一个可编程的网络代理,允许开发者控制页面上拍卖的网络请求。
  • 在不被使用的时候,它会友善终止,而当它再也被用到的时候,会被重新激活,所以你不可能依靠于service
    worker的onfecth和onmessage的处理函数中的全局状态。若是您想要保存一些持久化的信息,你可以在service
    worker里使用IndexedDB API。
  • Serviceworker大批量使用promise,所以只要您不明白哪些是promise,那你必要先读书这篇文章。

离线无缓存情况

会浮现一个默许的页面

亚洲必赢官网 8

-EOF-

打赏支持我写出更加多好小说,谢谢!

打赏小编

展开阅读

除此以外,还有多少个很棒的离线功用案例。如:Guardian 构建了一个有着 crossword
puzzle(填字游戏)的离线
web 页面 –
因此,尽管等待网络重连时(即已在离线状态下),也能找到一点乐趣。我也引进看看
Google Chrome Github
repo,它涵盖了诸多不相同的
Service Worker 案例 – 其中部分使用案例也在这!

可是,如若您想跳过上述代码,只是想差不多地经过一个库来拍卖相关操作,那么我引进您看看
UpUp。那是一个轻量的剧本,能让你更自在地行使离线效能。

打赏援助我翻译更加多好作品,谢谢!

打赏译者

加紧效果

首页加速后,网络请求从16降为1,加载时间从2.296s降为0.654s,得到了瞬间加载的结果。

亚洲必赢官网 9

基于webpagetest

查看测试结果

瑟维斯(Service) Worker的生命周期

Service worker拥有一个截然独立于Web页面的生命周期。

要让一个service
worker在您的网站上生效,你须求先在你的网页中注册它。注册一个service
worker之后,浏览器会在后台默默启动一个service worker的装置进度。

在安装进程中,浏览器会加载并缓存一些静态资源。如果具有的文本被缓存成功,service
worker就设置成功了。假使有任何文件加载或缓存失利,那么安装进程就会破产,service
worker就不能够被激活(也即没能安装成功)。假诺暴发如此的问题,别担心,它会在下次再尝试安装。

当安装到位后,service
worker的下一步是激活,在这一阶段,你仍能提高一个service
worker的本子,具体内容我们会在后边讲到。

在激活之后,service
worker将接管所有在和谐管辖域范围内的页面,可是假使一个页面是刚刚注册了service
worker,那么它那四遍不会被接管,到下几回加载页面的时候,service
worker才会生效。

当service
worker接管了页面之后,它或许有三种意况:要么被为止以节本省存,要么会处理fetch和message事件,那七个事件分别发出于一个网络请求现身依旧页面上发送了一个音讯。

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

亚洲必赢官网 10

打赏接济自己写出越来越多好文章,谢谢!

任选一种支付办法

亚洲必赢官网 11
亚洲必赢官网 12

1 赞 1 收藏
评论

打赏支持自己翻译更加多好小说,谢谢!

任选一种支付办法

亚洲必赢官网 13
亚洲必赢官网 14

1 赞 3 收藏 1
评论

加紧/离线原理探索

在我们开始写码以前

从这个花色地址拿到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得到一个TLS证书。分裂的server安装方法分裂,阅读帮忙文档并通过Mozilla’s
SSL config
generator询问最佳实践。

关于小编:pangjian

亚洲必赢官网 15

庞健,金融IT男。
个人主页 ·
我的稿子 ·
5 ·
  

亚洲必赢官网 16

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

亚洲必赢官网 17

前端,在路上…
个人主页 ·
我的作品 ·
19 ·
    

亚洲必赢官网 18

什么是 Service worker

亚洲必赢官网 19

如上图,Service
worker

是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当一个页面注册了一个
Service
worker
,它就足以登记一文山会海事件处理器来响应如网络请求和信息推送这个事件。Service
worker

可以被用来治本缓存,当响应一个网络请求时方可配备为回到缓存照旧从网络获取。由于Service
worker

是根据事件的,所以它只在拍卖那几个事件的时候被调入内存,不用操心常驻内存占用资源导致系统变慢。

使用Service Worker

近期大家有了polyfill,并且搞定了HTTPS,让大家看看到底怎么用service
worker。

Service(Service) worker生命周期

亚洲必赢官网 20

Service
worker

为网页添加一个接近于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是否对你的网站启用了。

亚洲必赢官网 21

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

你会发觉这一个成效可以很有益地在一个模拟窗口中测试你的service
worker,这样您可以关闭和另行打开它,而不会影响到你的新窗口。任何创设在模拟窗口中的注册服务和缓存在窗口被关闭时都将熄灭。

Service(Service) worker的主宰从第二次页面访问开首

在第一次加载页面时,所有资源都是从网络载的,Service
worker

在首次加载时不会收获控制网络响应,它只会在继承访问页面时起效果。

亚洲必赢官网 22

页面首次加载时做到install,并跻身idle状态。

亚洲必赢官网 23

页面第二次加载时,进入activated状态,准备处理所有的轩然大波,同时
浏览器会向服务器发送一个异步 请求来检查Service
worker
我是或不是有新的本子,构成了Service
worker
的立异机制。

亚洲必赢官网 24

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就设置成功了。假若其余一个文件下载失利,那么安装步骤就会破产。这几个点子允许你依靠于你协调指定的有所资源,不过那代表你须要非常战战兢兢地控制如何文件须要在装置步骤中被缓存。指定了太多的公文的话,就会增多设置失利率。

地点只是一个简单的例子,你可以在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所处的环境是互为隔离的。

亚洲必赢官网 25

  • 未曾浏览页面时也得以运行

收起系统事件,后台运行

  • 事件驱动,须要时运行,不要求时就截至

按需执行,只在急需时加载到内存

  • 可升级

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

何以缓存和返回Request

您早就设置了service worker,你现在可以重回您缓存的请求了。

当service
worker被装置成功还要用户浏览了另一个页面或者刷新了现阶段的页面,service
worker将启幕接受到fetch事件。下边是一个事例:

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只好被读取三次,所以大家得将它克隆出来,一份发给浏览器,一份发给缓存。

贯彻加快/离线

什么样创新一个瑟维斯(Service)(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的时候立时执行它,那么照旧在运转的旧版本的数据就坏了。

事先大家只利用了一个缓存,叫做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>

若是浏览器支持serviceWorker就报了名它,不支持照旧健康浏览,没有Service
worker
所提供的加强效率。

Service(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)(Service) Workers

fetch马上辅助在页面上行使了,不过近期的Chrome完成,它还只援救service
worker。cache
API也快要在页面上被帮衬,但是近来甘休,cache也还只可以在service
worker中用。

install

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’
})

如此那般设计是有理由的,它比XHR的在同源下默许发送凭据,但跨域时放任凭据的条条框框要来得好。fetch的行为更像其余的CORS请求,例如<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-CORS默许不扶助

默许意况下,从第三方URL跨域获得一个资源将会破产,除非对方援救了CORS。你可以加上一个non-CORS选项到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版本图片

正如好的方案是2或3,因为假使把具备的图样都给下载下来存着有点浪费内存。

一经你将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替代,假如从前它早已被缓存过。固然如此,由于现在的格局是2x,浏览器会把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;" />

亚洲必赢官网 26

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

一定网站

  1. Google Chrome

Developer Tools->Application->Service Workers

亚洲必赢官网 27

在那里还有几个越发实用的复选框:

  • Offline

效仿断网状态

  • Update on reload
    加载时更新
  • Bypass for network
    连日利用网络内容
  1. Firefox

除非在Settings里有一个可以在HTTP环境中应用Service
worker
的选项,适应于调试,没有单独网站下的Service
worker
管理。

亚洲必赢官网 28

  1. Opera及别的双核浏览器同谷歌(Google) Chrome
    如若看到多个一样范围内的几个Service
    worker
    ,说明Service
    woker
    更新后,而原有Service
    worker
    还未曾被terminated。

改变URL Hash的Bug

在M40版本中存在一个bug,它会让页面在变更hash的时候造成service
worker为止工作。

您可以在此间找到更加多相关的新闻: 

浏览器全局

看看您的浏览器里都有哪些瑟维斯(Service)(Service) worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

可以看来曾经有24个Serviceworker了,在此间可以手动Start让它工作,也足以Unregister卸载掉。

亚洲必赢官网 29

  1. Firefox

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

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

JavaScript

about:debugging#workers

1
about:debugging#workers

亚洲必赢官网 30

  1. Opera及此外双核浏览器同谷歌 Chrome

更加多内容

此处有部分有关的文档可以参照:

更多

TODO:

  • Service
    workers
    的换代须求手动编辑version,每一趟发表新文章时必要编制。
  • 使用AMP让页面渲染速度高达最高。

获得支持

如若你遇上麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家马上跟进和不择手段辅助你解决问题。

赞 2 收藏
评论

亚洲必赢官网 31

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 收藏
评论

亚洲必赢官网 32

网站地图xml地图