大不列颠及英格兰联合王国卫报的秉性离线页面是这般做的,离线访问静态blog网站

应用Service(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上有着这一个功用成为可能。

连不上网?大英帝国卫报的天性离线页面是这样做的

2015/11/20 · HTML5 · Service
Worker,
离线页面

本文由 伯乐在线 –
Erucy
翻译,weavewillg
校稿。未经许可,禁止转载!
英文出处:Oliver
Ash。欢迎插手翻译组。

咱俩是怎么运用 service worker 来为 theguardian.com
构建一个自定义的离线页面。

澳门葡京 1

theguardian.com 的离线页面。插图:Oliver(Oliver) Ash

您正在朝着集团途中的地铁里,在手机上打开了
Guardian
应用。地铁被隧道包围着,不过那一个利用可以正常运行,即便没有网络连接,你也能获取完全的意义,除了体现的内容可能有点旧。如若您品味在网站上也这么干,可惜它完全没法加载:

澳门葡京 2

安卓版 Chrome 的离线页面

Chrome 中的这几个彩蛋,很两人都不精通》

Chrome
在离线页面上有个暗藏的游乐(桌面版上按空格键,手机版上点击这只恐龙),这有些能减轻一点你的困扰。不过大家得以做得更好。

Service
workers
允许网站作者拦截自己站点的兼具网络请求,这也就表示我们可以提供系数的离线体验,就像原生应用相同。在
Guardian
网站,大家多年来上线了一个自定义的离线体验效果。当用户离线的时候,他们会面到一个暗含
Guardian
标识的页面,上边带有一个简单的离线提醒,还有一个填字游戏,他们得以在守候网络连接的时候玩玩这多少个找点乐子。这篇博客解释了大家是怎么构建它的,可是在始发以前,你可以先自己试试看。

采纳 瑟维斯(Service)(Service) worker 创造一个非凡简单的离线页面

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

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

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

澳门葡京 3

这是一对一令人沮丧的经验!幸运的是,web
开发者们能透过有些新特性来改善这类的用户体验。我近年径直在折腾 瑟维斯(Service)(Service)Workers,它给 web 带来的无尽可能性总能给本人惊喜。Service(Service) Workers
的可观特质之一是同意你检测网络请求的现象,并让你作出相应的响应。

在这篇著作里,我打算用此特性检查用户的脚下网络连接情状,假如没连接则赶回一个最佳简单的离线页面。即使那是一个异常基础的案例,但它能给您带来启迪,让你精晓启动并运行该特性是多么的简约!假诺您没精晓过
瑟维斯(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\//, ]大不列颠及英格兰联合王国卫报的秉性离线页面是这般做的,离线访问静态blog网站。;

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

澳门葡京 4

在根目录下添加offline.html,在一直不网络且缓存中也远非时选拔,效果如下:

澳门葡京 5

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

Service Worker 是什么?

一个 service worker
是一段运行在浏览器后台进程里的本子,它独立于近期页面,提供了这么些不需要与web页面交互的效果在网页背后悄悄执行的力量。在未来,基于它可以实现消息推送,静默更新以及地理围栏等服务,不过如今它首先要负有的效益是掣肘和处理网络请求,包括可编程的响应缓存管理。

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

在service worker指出此前,此外一个提供开发者离线体验的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,这你需要先读书这篇文章。

试试看

你需要一个支撑 Service
Worker 和 fetch
API 的浏览器。截至到本文编写时只有Chrome(手机版和桌面版)同时补助这二种 API(译者注:Opera
目前也协理这六头),不过 Firefox
很快就要襄助了(在每一日更新的本子中早就辅助了),除去 Safari
之外的拥有浏览器也都在试行。其余,service worker 只好登记在利用了
HTTPS 的网站上,theguardian.com
已经起来渐渐搬迁到 HTTPS,所以我们只能在网站的 HTTPS
部分提供离线体验。就现阶段来说,我们接纳了 开发者博客 作为我们用来测试的地点。所以只要您是在大家网站的 开发者博客 部分阅读这篇小说的话,很幸运。

当你利用扶助的浏览器访问咱们的 开发者博客 中的页面的时候,一切就准备妥当了。断开你的网络连接,然后刷新一下页面。倘诺你协调没规范尝试的话,可以看一下这段 示范视频(译者注:需梯子)。

让大家起始吧

假定你有以下 HTML 页面。这尽管这个基础,但能给您完全思路。

XHTML

<!DOCTYPE html>

1
<!DOCTYPE html>

随后,让我们在页面里登记 Service(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 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)(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 访问网络)

澳门葡京 6

倘诺您刷新页面,你应该能观算命应的离线页面!

澳门葡京 7

假定你只想大概地测试该意义而不想写任何代码,那么你可以访问我已开立好的
demo。其它,上述总体代码可以在
Github repo 找到。

自家精晓用在此案例中的页面很粗略,但您的离线页面则取决于你协调!假若你想深刻该案例的情节,你可以为离线页面添加缓存破坏(
cache busting),如:
此案例。

增速效果

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

澳门葡京 8

基于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初次安装的生命周期:

澳门葡京 9

办事规律

透过一段简单的
JavaScript,我们得以指示浏览器在用户访问页面的时候立时登记我们自己的
service worker。近来支撑 service worker
的浏览器很少,所以为了避免不当,大家需要接纳特性检测。

JavaScript

if (navigator.serviceWorker) {
navigator.serviceWorker.register(‘/service-worker.js’); }

1
2
3
if (navigator.serviceWorker) {
    navigator.serviceWorker.register(‘/service-worker.js’);
}

瑟维斯(Service) worker
安装事件的一有的,我们得以利用 新的缓存
API 来缓存我们网站中的各类内容,比如
HTML、CSS 和
JavaScript:

JavaScript

var staticCacheName = ‘static’; var version = 1; function updateCache()
{ return caches.open(staticCacheName + version) .then(function (cache) {
return cache.addAll([ ‘/offline-page.html’, ‘/assets/css/main.css’,
‘/assets/js/main.js’ ]); }); }; self.addEventListener(‘install’,
function (event) { event.waitUntil(updateCache()); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var staticCacheName = ‘static’;
var version = 1;
 
function updateCache() {
    return caches.open(staticCacheName + version)
        .then(function (cache) {
            return cache.addAll([
                ‘/offline-page.html’,
                ‘/assets/css/main.css’,
                ‘/assets/js/main.js’
            ]);
        });
};
 
self.addEventListener(‘install’, function (event) {
    event.waitUntil(updateCache());
});

当安装到位后,service worker
可以监听和操纵 fetch
事件,让我们可以完全控制之后网站中暴发的装有网络请求。

JavaScript

self.addEventListener(‘fetch’, function (event) {
event.respondWith(fetch(event.request)); });

1
2
3
self.addEventListener(‘fetch’, function (event) {
    event.respondWith(fetch(event.request));
});

在此间大家有很灵巧的半空中可以发表,比如上边这个问题,可以透过代码来生成咱们友好的哀求响应:

JavaScript

self.addEventListener(‘fetch’, function (event) { var response = new
Response(‘<h1>Hello, World!</h1>’, { headers: {
‘Content-Type’: ‘text/html’ } }); event.respondWith(response); });

1
2
3
4
5
self.addEventListener(‘fetch’, function (event) {
    var response = new Response(‘&lt;h1&gt;Hello, World!&lt;/h1&gt;’,
        { headers: { ‘Content-Type’: ‘text/html’ } });
    event.respondWith(response);
});

再有这一个,倘使在缓存中找到了请求相应的缓存,大家得以一向从缓存中回到它,假如没找到的话,再通过网络获取响应内容:

JavaScript

self.addEventListener(‘fetch’, function (event) { event.respondWith(
caches.match(event.request) .then(function (response) { return response
|| fetch(event.request); }) ); });

1
2
3
4
5
6
7
8
self.addEventListener(‘fetch’, function (event) {
    event.respondWith(
        caches.match(event.request)
            .then(function (response) {
                return response || fetch(event.request);
            })
    );
});

这就是说我们什么样采用这么些意义来提供离线体验呢?

第一,在 service worker
安装过程中,大家需要把离线页面需要的 HTML 和资源文件通过 service worker
缓存下来。在缓存中,我们加载了团结付出的 填字游戏 的
React应用 页面。之后,我们会阻拦所有访问
theguardian.com
网络请求,包括网页、以及页面中的资源文件。处理这一个请求的逻辑大致如下:

  1. 当大家检测到传播请求是指向我们的 HTML
    页面时,大家总是会想要提供最新的情节,所以我们会尝试把这个请求通过网络发送给服务器。

    1. 当我们从服务器得到了响应,就可以间接重返那个响应。
    2. 假设网络请求抛出了要命(比如因为用户掉线了),我们捕获这么些可怜,然后使用缓存的离线
      HTML 页面作为响应内容。
  2. 要不然,当我们检测到请求的不是 HTML
    的话,我们会从缓存中检索响应的伸手内容。

    1. 一旦找到了缓存内容,大家可以直接再次回到缓存的始末。
    2. 不然,大家会尝试把这多少个请求通过网络发送给服务器。

在代码中,我们应用了 新的缓存
API(它是 瑟维斯(Service)(Service) Worker API 的一部分)以及
fetch
效用(用于转移网络请求),如下所示:

JavaScript

var doesRequestAcceptHtml = function (request) { return
request.headers.get(‘Accept’) .split(‘,’) .some(function (type) { return
type === ‘text/html’; }); }; self.addEventListener(‘fetch’, function
(event) { var request = event.request; if
(doesRequestAcceptHtml(request)) { // HTML pages fallback to offline
page event.respondWith( fetch(request) .catch(function () { return
caches.match(‘/offline-page.html’); }) ); } else { // Default fetch
behaviour // Cache first for all other requests event.respondWith(
caches.match(request) .then(function (response) { return response ||
fetch(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
25
26
27
var doesRequestAcceptHtml = function (request) {
    return request.headers.get(‘Accept’)
        .split(‘,’)
        .some(function (type) { return type === ‘text/html’; });
};
 
self.addEventListener(‘fetch’, function (event) {
    var request = event.request;
    if (doesRequestAcceptHtml(request)) {
        // HTML pages fallback to offline page
        event.respondWith(
            fetch(request)
                .catch(function () {
                    return caches.match(‘/offline-page.html’);
                })
        );
    } else {
        // Default fetch behaviour
        // Cache first for all other requests
        event.respondWith(
            caches.match(request)
                .then(function (response) {
                    return response || fetch(request);
                })
        );
    }
});

就只需要如此多!theguardian.com
上的 不无代码都是在 GitHub
上开源 的,所以您可以去这儿查看大家的
service worker
的全体版本,或者间接从生产条件上访问

咱俩有充分的说辞为这一个新的浏览器技术欢呼喝彩,因为它能够用来让您的网站像前些天的原生应用相同,拥有完善的离线体验。将来当
theguardian.com 完全迁移到 HTTPS
之后,离线页面的重要性性会显然增多,我们可以提供越来越圆满的离线体验。设想一下您在上下班路上网络很差的时候访问
theguardian.com,你会看出专门为您订制的个性化内容,它们是在你以前访问网站时由浏览器缓存下来的。它在安装过程中也不会爆发此外艰辛,你所需要的只是造访这些网站而已,不像原生应用,还需要用户有一个使用集团的账号才能设置。Serviceworker
同样可以扶持大家提高网站的加载速度,因为网站的框架可以被保险地缓存下来,就像原生应用相同。

要是你对 service worker
很感兴趣,想要了然更多内容的话,开发者 Matt
Gaunt(Chrome的忠贞襄助者)写了一篇更加详细地 介绍 Service
Worker的文章。

打赏帮忙自己翻译更多好著作,谢谢!

打赏译者

进展阅读

此外,还有多少个很棒的离线功效案例。如:Guardian 构建了一个怀有 crossword
puzzle(填字游戏)的离线
web 页面 –
因而,即便等待网络重连时(即已在离线状态下),也能找到一点乐趣。我也援引看看
Google Chrome Github
repo,它含有了不少两样的
Service(Service) Worker 案例 – 其中有的采用案例也在这!

唯独,假如你想跳过上述代码,只是想大概地因而一个库来处理相关操作,那么自己推荐你看看
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拿到一个TLS证书。不同的server安装方法不同,阅读协助文档并经过Mozilla’s
SSL config
generator领会最佳实践。

打赏帮助自己翻译更多好著作,谢谢!

澳门葡京 10

1 赞 收藏
评论

打赏辅助自己翻译更多好作品,谢谢!

任选一种支付办法

澳门葡京 11
澳门葡京 12

澳门葡京, 1 赞 3 收藏 1
评论

什么是 Service worker

澳门葡京 13

如上图,Service
worker

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

可以被用来治本缓存,当响应一个网络请求时能够安排为回去缓存仍然从网络得到。由于Service
worker

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

使用Service Worker

最近大家有了polyfill,并且搞定了HTTPS,让我们看看究竟怎么用service
worker。

有关作者:Erucy

澳门葡京 14

现已的SharePoint喵星程序猿(暂时还挂着微软MVP的名头),现在的Azure/.Net/MongoDB/Cordova/前端程序猿,偶尔写小说
个人主页 ·
我的篇章 ·
46 ·
  

澳门葡京 15

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

澳门葡京 16

前端,在路上…
个人主页 ·
我的篇章 ·
19 ·
    

澳门葡京 17

Service worker生命周期

澳门葡京 18

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

澳门葡京 19

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

您会意识这些效果可以很有益于地在一个模仿窗口中测试你的service
worker,这样您可以关闭和重新打开它,而不会影响到你的新窗口。任何创立在模拟窗口中的注册服务和缓存在窗口被关闭时都将消灭。

瑟维斯(Service) worker的决定从第二次页面访问起首

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

在第一次加载时不会博得控制网络响应,它只会在继承访问页面时起效果。

澳门葡京 20

页面第一次加载时成功install,并跻身idle状态。

澳门葡京 21

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

澳门葡京 22

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)(Service) Worker 代码中运用 localStorage。

  • 单独的实践环境

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

  • 从未绑定到特定页面

service work能说了算它所加载的任何范围内的资源。

  • 无法操作DOM

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

澳门葡京 23

  • 从没浏览页面时也得以运作

吸纳系统事件,后台运行

  • 事件驱动,需要时运行,不需要时就终止

按需实施,只在需要时加载到内存

  • 可升级

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

怎么缓存和重回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;" />

澳门葡京 24

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

特定网站

  1. Google Chrome

Developer Tools->Application->Service Workers

澳门葡京 25

在此地还有五个要命管用的复选框:

  • Offline

如法炮制断网状态

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

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

澳门葡京 26

  1. Opera及此外双核浏览器同Google 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/

可以见到曾经有24个瑟维斯(Service)worker了,在此间可以手动Start让它工作,也可以Unregister卸载掉。

澳门葡京 27

  1. Firefox

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

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

JavaScript

about:debugging#workers

1
about:debugging#workers

澳门葡京 28

  1. Opera及其他双核浏览器同Google Chrome

更多内容

此地有一部分息息相关的文档可以参见:

更多

TODO:

  • Service
    workers
    的更新需要手动编辑version,每一趟宣布新作品时索要编制。
  • 使用AMP让页面渲染速度高达最高。

得到襄助

一经你遇上麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于我们立即跟进和尽可能协助你解决问题。

赞 2 收藏
评论

澳门葡京 29

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

澳门葡京 30

相关文章

发表评论

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

*
*
Website