【必发88】成立一个非凡简单的离线页面,利用serviceworker的离线访问情势

by admin on 2019年1月31日

迈向PWA!利用serviceworker的离线访问情势

2017/02/08 · JavaScript
· PWA

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

微信小程序来了,可以应用WEB技术在微信创设一个所有Native应用经验的利用,业界分外看好那种格局。不过你们可能不领会,谷歌(Google)早已有类似的宏图,甚至层次更高。那就是PWA(渐进式增强WEB应用)。
PWA有以下二种特性:

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

抱有那个特征都是“优雅降级、渐进增强的”,给协助的配备更好的体会,不援助的装备也不会更差。那就和微信小程序那种糟糕设计的平昔分歧之处。

本博客也在向着PWA的大方向迈进,第一步我选拔了Offline,也就是离线能力。可以让客户在未曾网络连接的时候仍是可以运用部分服务。那一个力量运用了ServiceWorker技术。

心想事成思路就是,利用service
worker,另起一个线程,用来监听所有网络请求,讲曾经呼吁过的数额放入cache,在断网的情事下,直接取用cache里面的资源。为呼吁过的页面和图表,显示一个默认值。当有互联网的时候,再重新从服务器更新。
必发88 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 worker 创立一个分外简单的离线页面

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

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

让我们想像以下意况:我们那时候在一辆通往农村的列车上,用运动设备望着一篇很棒的稿子。与此同时,当您点击“查看愈来愈多”的链接时,火车忽然进入了隧道,导致移动设备失去了互连网,而
web 页面会显示出类似以下的始末:

必发88 2

那是一对一令人懊恼的体会!幸运的是,web
开发者们能经过一些新特点来改良这类的用户体验。我多年来一贯在折腾 ServiceWorkers,它给 web 带来的无尽可能性总能给自己惊喜。Service Workers
的脍炙人口特质之一是允许你检测互连网请求的光景,并让您作出相应的响应。

在这篇小说里,我打算用此特性检查用户的脚下互连网连接景况,要是没连接则赶回一个极品不难的离线页面。即便那是一个相当基础的案例,但它能给您带来启迪,让你掌握启动并运行该特性是多么的简要!假若您没通晓过
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,由于静态内容的特色分外适合做缓存来加快页面的访问,就选用Service
worker
来促成加速,结果是除了PageSpeed,CDN那个周边的服务器和互连网加速之外,通过客户端落成了更好的拜访体验。

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

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

  • 十年踪迹]()   

原生App拥有Web应用一般所不具有的富离线体验,定时的沉默更新,音讯通告推送等职能。而新的Serviceworkers标准让在Web App上享有那些效应成为可能。

离线有缓存情形

必发88 3

让大家起首吧

只要你有以下 HTML 页面。那固然可怜基础,但能给您完全思路。

【必发88】成立一个非凡简单的离线页面,利用serviceworker的离线访问情势。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(‘ServiceWorker 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
      ]);
    })
  );
});

在上头的代码中,大家在设置 Service Worker
时,向缓存添加了离线页面。假使我们将代码分为几小块,可寓近来几行代码中,我为离线页面指定了缓存版本和URL。即使你的缓存有例外版本,那么您只需立异版本号即可不难地解除缓存。在大约在第
12
行代码,我向那么些离线页面及其资源(如:图片)发出请求。在取得成功的响应后,大家将离线页面和有关资源丰硕到缓存。

今日,离线页面已存进缓存了,大家可在急需的时候检索它。在同一个 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 访问网络)

必发88 4

假若你刷新页面,你应有能看到相应的离线页面!

必发88 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?:\【必发88】成立一个非凡简单的离线页面,利用serviceworker的离线访问情势。/\/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都引用了什么样第三方资源,逐个加到忽略列表里。

必发88 6

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

必发88 7

在根目录下添加offline.svg,在无网络时图片资源请求重临该公文。

Service Worker 是什么?

一个 service worker
是一段运行在浏览器后台进度里的剧本,它独立于当下页面,提供了那一个不要求与web页面交互的成效在网页背后悄悄执行的力量。在今天,基于它可以兑现音信推送,静默更新以及地理围栏等劳动,但是当前它首先要具备的意义是阻止和拍卖网络请求,包蕴可编程的响应缓存管理。

干什么说那几个API是一个不胜棒的API呢?因为它使得开发者可以援救越发好的离线体验,它赋予开发者完全控制离线数据的能力。

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

上边详细说一下service worker有哪些须要专注的地点:

  • 必发88,它是JavaScript
    Worker,所以它不能直接操作DOM。可是service
    worker能够透过postMessage与页面之间通讯,把新闻通知给页面,要是需求的话,让页面自己去操作DOM。
  • Serviceworker是一个可编程的网络代理,允许开发者控制页面上处理的网络请求。
  • 在不被利用的时候,它会友善终止,而当它再也被用到的时候,会被另行激活,所以您无法依靠于service
    worker的onfecth和onmessage的处理函数中的全局状态。即使您想要保存一些持久化的音信,你可以在service
    worker里使用IndexedDB API。
  • Serviceworker大批量使用promise,所以如若您不打听怎样是promise,那你要求先读书这篇文章。

离线无缓存情形

会来得一个默许的页面

必发88 8

-EOF-

打赏帮忙自己写出越来越多好小说,谢谢!

打赏作者

进行阅读

其余,还有多少个很棒的离线效用案例。如:Guardian 构建了一个具备 crossword
puzzle(填字游戏)的离线
web 页面 –
由此,就算等待互联网重连时(即已在离线状态下),也能找到一点乐趣。我也援引看看
Google Chrome Github
repo,它包括了好多例外的
Service Worker 案例 – 其中一部分用到案例也在那!

但是,即使您想跳过上述代码,只是想大概地通过一个库来处理有关操作,那么我引进您看看
UpUp。那是一个轻量的台本,能让您更自在地利用离线成效。

打赏扶助自己翻译更加多好文章,谢谢!

打赏译者

增速效果

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

必发88 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初次安装的生命周期:

必发88 10

打赏支持自己写出越多好小说,谢谢!

任选一种支付形式

必发88 11
必发88 12

1 赞 1 收藏
评论

打赏协助我翻译更加多好小说,谢谢!

任选一种支付办法

必发88 13
必发88 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

必发88 15

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

必发88 16

有关小编:刘健超-J.c

必发88 17

前端,在路上…
个人主页 ·
我的小说 ·
19 ·
    

必发88 18

什么是 Service worker

必发88 19

如上图,Service
worker

是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当一个页面注册了一个
Service
worker
,它就能够挂号一多重事件处理器来响应如网络请求和新闻推送这个事件。Service
worker

可以被用来管理缓存,当响应一个互联网请求时方可布署为回到缓存依然从互连网得到。由于Service
worker

是依照事件的,所以它只在拍卖这几个事件的时候被调入内存,不用顾虑常驻内存占用资源导致系统变慢。

使用Service Worker

当今大家有了polyfill,并且搞定了HTTPS,让我们看看到底怎么用service
worker。

Service worker生命周期

必发88 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是否对你的网站启用了。

必发88 21

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

您会发觉那几个职能能够很有利地在一个效仿窗口中测试你的service
worker,那样你可以关闭和重复打开它,而不会潜移默化到您的新窗口。任何成立在模仿窗口中的注册服务和缓存在窗口被关门时都将没有。

Service worker的操纵从第二次页面访问开端

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

在首次加载时不会得到控制网络响应,它只会在接二连三访问页面时起效果。

必发88 22

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

必发88 23

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

必发88 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
是阻塞性,所以不该在 Service Worker 代码中接纳 localStorage。

  • 单独的推行环境

Service
worker
运转在团结的大局环境中,寻常也运行在自己独自的线程中。

  • 没有绑定到特定页面

service work能决定它所加载的全部范围内的资源。

  • 不能操作DOM

跟DOM所处的环境是并行隔离的。

必发88 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 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 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

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;" />

必发88 26

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

特定网站

  1. Google Chrome

Developer Tools->Application->Service Workers

必发88 27

在那里还有几个更加实用的复选框:

  • Offline

如法泡制断网状态

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

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

必发88 28

  1. Opera及别的双核浏览器同谷歌 Chrome
    假诺看到多少个一律范围内的多个Service
    worker
    ,说明Service
    woker
    更新后,而原有Service
    worker
    还未曾被terminated。

改变URL Hash的Bug

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

你可以在那里找到更多相关的音信: 

浏览器全局

看望您的浏览器里都有如何瑟维斯 worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

可以见见已经有24个Serviceworker了,在那里可以手动Start让它工作,也足以Unregister卸载掉。

必发88 29

  1. Firefox

有二种艺术进入Service
worker
管理界面来手动Start或unregister。

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

JavaScript

about:debugging#workers

1
about:debugging#workers

必发88 30

  1. Opera及其余双核浏览器同谷歌 Chrome

越来越多内容

那边有局地城门失火的文档可以参照:

更多

TODO:

  • Service
    workers
    的翻新须求手动编辑version,每一次发表新小说时必要编制。
  • 使用AMP让页面渲染速度达到最高。

得到赞助

若果您遇见麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家当即跟进和尽可能协助您解决难题。

赞 2 收藏
评论

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

必发88 32

发表评论

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

网站地图xml地图