澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站大不列颠及苏格兰联合王国

2019-05-17 作者:澳门新萄京赌场网址   |   浏览(78)

利用 Service worker 创立一个特别轻松的离线页面

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

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

让我们想像以下处境:大家那时候在1辆通往农村的列车里,用运动设备瞅着1篇很棒的篇章。与此同时,当您点击“查看更加多”的链接时,轻轨忽然进入了隧道,导致移动设备失去了互连网,而 web 页面会彰显出类似以下的剧情:

澳门新萄京官方网站 1

这是一定令人颓败的体会!幸运的是,web 开辟者们能透过有些新性情来改进那类的用户体验。小编最近径直在折腾 ServiceWorkers,它给 web 带来的数不清或然性总能给本身欣喜。Service Workers 的名特别减价特质之1是同意你检查测试互连网请求的风貌,并令你作出相应的响应。

在那篇小说里,小编筹划用此天性检查用户的当前网络连接境况,假诺没连接则赶回二个一级轻巧的离线页面。固然这是1个不胜基础的案例,但它能给你带来启迪,让您精通运转并运营该性情是多么的简便!即便你没驾驭过 Service Worker,笔者提议您看看此 Github repo,掌握越来越多相关的音讯。

在该案例初始前,让大家先轻巧地看看它的行事流程:

  1. 在用户第三遍访问我们的页面时,我们会安装 ServiceWorker,并向浏览器的缓存增加大家的离线 HTML 页面
  2. 然后,假若用户图谋导航到另二个 web 页面(同3个网址下),但此时已断网,那么我们将赶回已被缓存的离线 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那个大规模的服务器和网络加快之外,通过客户端达成了越来越好的访问体验。

连不上网?英帝国卫报的性子离线页面是那般做的

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

本文由 伯乐在线 - Erucy 翻译,weavewillg 校稿。未经许可,禁止转发!
英文出处:Oliver Ash。应接出席翻译组。

大家是什么选择 service worker 来为 theguardian.com 构建3个自定义的离线页面。

澳门新萄京官方网站 2

theguardian.com 的离线页面。插图:奥利弗 Ash

您正在朝着集团途中的大巴里,在手提式有线电电话机上张开了 Guardian 应用。地铁被隧道包围着,可是那些利用能够符合规律运维,纵然未有互联网连接,你也能获得完全的效果,除了展现的内容也可以有点旧。假诺您品味在网址上也这么干,可惜它完全没法加载:

澳门新萄京官方网站 3

安卓版 Chrome 的离线页面

Chrome 中的那些彩蛋,很三个人都不领会》

Chrome 在离线页面上有个藏匿的游艺(桌面版上按空格键,手提式有线电电话机版上点击那只恐龙),那某个能缓解一点您的苦闷。可是大家能够做得更加好。

Service workers 允许网址作者拦截本人站点的享有互联网请求,这也就象征大家得以提供完善的离线体验,就好像原生应用同样。在 Guardian 网址,大家近年来上线了2个自定义的离线体验效果。当用户离线的时候,他们会看到多个涵盖 Guardian 标志的页面,上面带有三个简易的离线提示,还有三个填字游戏,他们能够在等待互连网连接的时候玩玩那一个找点乐子。那篇博客解释了笔者们是何等创设它的,但是在初始以前,你能够先自个儿研究看。

Service Worker入门

2015/03/26 · JavaScript · Service Worker

原来的小说出处: Matt Gaunt   译文出处:[w3ctech

  • 十年踪迹]()   

原生App具备Web应用普通所不负有的富离线体验,按期的守口如瓶更新,音信通知推送等效率。而新的Serviceworkers规范让在Web App上全数那个职能成为恐怕。

应用 Service Worker 做一个 PWA 离线网页应用

2017/10/09 · JavaScript · PWA, Service Worker

原稿出处: 人人网FED博客   

在上一篇《自己是什么样让网址用上HTML5Manifest》介绍了怎么用Manifest做一个离线网页应用,结果被广泛网上死党调侃说这些事物已经被deprecated,移出web标准了,以后被ServiceWorker代替了,不管如何,Manifest的部分想想还可以借用的。作者又将网址晋级到了ServiceWorker,若是是用Chrome等浏览器就用ServiceWorker做离线缓存,如若是Safari浏览器就照旧用Manifest,读者可以展开那个网址感受一下,断网也是能健康张开。

让咱们伊始吧

假设你有以下 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('瑟维斯Worker 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‘。大家筹算用那么些 瑟维斯 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 时,向缓存增加了离线页面。若是大家将代码分为几小块,可看到前几行代码中,小编为离线页面钦点了缓存版本和U凯雷德L。若是您的缓存有例外版本,那么你只需革新版本号就能够轻易地清除缓存。在差不多在第叁二行代码,作者向这么些离线页面及其能源(如:图片)发出请求。在收获成功的响应后,大家将离线页面和有关能源丰硕到缓存。

到现在,离线页面已存进缓存了,大家可在急需的时等候检查索它。在同多个 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 访问互联网)

澳门新萄京官方网站 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 和 fetch API 的浏览器。停止到本文编写时只有Chrome(手提式有线电话机版和桌面版)同时帮助那二种 API(译者注:Opera 近日也帮助那两个),不过 Firefox 相当的慢将要支持了(在天天更新的版本中早已支撑了),除外 Safari 之外的具备浏览器也都在尝试。其它,service worker 只能登记在选拔了 HTTPS 的网址上,theguardian.com 已经伊始慢慢搬迁到 HTTPS,所以我们只可以在网址的 HTTPS 部分提供离线体验。就方今以来,大家挑选了 开辟者博客 作为我们用来测试的地点。所以一旦你是在大家网址的 开拓者博客 部分阅读那篇小说的话,很幸运。

当你接纳援助的浏览器访问我们的 开拓者博客 中的页面包车型地铁时候,1切就计划稳妥了。断开你的网络连接,然后刷新一下页面。假诺您本身没标准尝试的话,能够看一下这段 躬体力行录制(译者注:需梯子)。

Service Worker 是什么?

3个 service worker 是1段运转在浏览器后台进程里的剧本,它独立于当下页面,提供了那叁个无需与web页面交互的功用在网页背后悄悄推行的力量。在以往,基于它能够兑现新闻推送,静默更新以及地理围栏等服务,可是当前它首先要具有的功用是阻挠和拍卖网络请求,包蕴可编制程序的响应缓存管理。

缘何说这么些API是二个丰盛棒的API呢?因为它使得开垦者能够支撑非常好的离线体验,它赋予开垦者完全调控离线数据的技能。

在service worker提议在此之前,此外三个提供开荒者离线体验的API叫做App Cache。可是App Cache某些局限性,比如它可以很轻松地化解单页应用的难题,不过在多页应用上会很麻烦,而Serviceworkers的现身正是为了解决App Cache的痛点。

下边详细说一下service worker有怎样须要留意的地点:

  • 它是JavaScript Worker,所以它不能够直接操作DOM。可是service worker能够通过postMessage与页面之间通讯,把新闻通告给页面,假诺须求的话,让页面自身去操作DOM。
  • Serviceworker是3个可编程的互连网代理,允许开采者调节页面上拍卖的网络请求。
  • 在不被利用的时候,它会融洽终止,而当它再也被用到的时候,会被重复激活,所以你不能够依赖于service worker的onfecth和onmessage的管理函数中的全局状态。假设你想要保存一些长久化的音信,你能够在service worker里使用IndexedDB API。
  • Serviceworker大批量使用promise,所以借使您不掌握什么是promise,那您必要先读书这篇文章。

1. 什么是Service Worker

Service Worker是谷歌(Google)发起的兑现PWA(Progressive Web App)的1个关键剧中人物,PWA是为着消除古板Web APP的老毛病:

(壹)未有桌面入口

(2)不能够离线使用

(3)没有Push推送

那Service Worker的具体表现是什么的吧?如下图所示:

澳门新萄京官方网站 8

ServiceWorker是在后台运转的一条服务Worker线程,上海教室我开了七个标签页,所以呈现了八个Client,可是不管开多少个页面都惟有一个Worker在担当管理。那几个Worker的办事是把一些资源缓存起来,然后拦截页面包车型大巴呼吁,先看下缓存Curry有未有,如若有个别话就从缓存里取,响应200,反之未有的话就走不奇怪的央浼。具体来讲,ServiceWorker结合Web App Manifest能成功以下专门的学业(那也是PWA的检查测试专门的学业):

澳门新萄京官方网站 9

席卷能够离线使用、断网时回来200、能提示用户把网址加多1个Logo到桌面上等。

实行阅读

别的,还有多少个很棒的离线功用案例。如:Guardian 构建了七个装有 crossword puzzle(填字游戏)的离线 web 页面 – 由此,就算等待网络重连时(即已在离线状态下),也能找到一点乐趣。笔者也援引看看 Google Chrome Github repo,它蕴涵了好些个两样的 Service Worker 案例 – 当中1部分运用案例也在那!

唯独,假若你想跳过上述代码,只是想大约地经过多个库来拍卖相关操作,那么自身引入您看看 UpUp。那是三个轻量的脚本,能让你更自在地选取离线作用。

打赏支持作者翻译越来越多好小说,多谢!

打赏译者

加快效果

首页加快后,互连网请求从16降为一,加载时间从二.2玖陆s降为0.65肆s,获得了须臾间加载的结果。

澳门新萄京官方网站 10

基于webpagetest

查看测试结果

行事原理

通过壹段轻便的 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 安装事件的1局地,大家能够使用 新的缓存 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. 假设互联网请求抛出了那1个(比方因为用户掉线了),大家捕获那么些可怜,然后使用缓存的离线 HTML 页面作为响应内容。
  2. 不然,当我们检查测试到请求的不是 HTML 的话,大家会从缓存中检索响应的请求内容。
    1. 固然找到了缓存内容,大家得以平昔回到缓存的内容。
    2. 不然,大家会尝试把这一个请求通过网络发送给服务器。

在代码中,大家选取了 新的缓存 API(它是 瑟维斯 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 的1体化版本,或然直接从生育蒙受上访问 。

咱俩有丰富的说辞为那一个新的浏览器本领欢呼喝彩,因为它能够用来让您的网址像今天的原生应用一样,具有完善的离线体验。现在当 theguardian.com 完全迁移到 HTTPS 之后,离线页面包车型客车机要性会鲜明增添,大家能够提供更加的全面包车型地铁离线体验。设想一下你在上下班路上网络很差的时候访问 theguardian.com,你相会到特地为您订制的本性化内容,它们是在你在此以前访问网址时由浏览器缓存下来的。它在设置进度中也不会生出别的困难,你所供给的只是造访这一个网址而已,不像原生应用,还亟需用户有七个用到市4的账号技术设置。Serviceworker 同样能够帮助大家提高网址的加载速度,因为网址的框架能够被保障地缓存下来,就像原生应用一样。

要是你对 service worker 很感兴趣,想要理解越来越多内容的话,开采者 MattGaunt(Chrome的忠实帮衬者)写了1篇特别详细地 介绍 Service Worker的文章。

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

打赏译者

Service Worker的生命周期

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

要让贰个service worker在你的网址上生效,你须要先在您的网页中注册它。注册2个service worker之后,浏览器会在后台默默运行贰个service worker的安装进度。

在安装进度中,浏览器会加载并缓存一些静态能源。假诺持有的公文被缓存成功,service worker就安装成功了。要是有其余公文加载或缓存退步,那么安装进程就能够失利,service worker就无法被激活(也即没能安装成功)。如若发生如此的难题,别顾忌,它会在下一次再品尝安装。

当安装到位后,service worker的下一步是激活,在这一品级,你还是可以升官二个service worker的本子,具体内容我们会在后头讲到。

在激活之后,service worker将接管全体在融洽管辖域范围内的页面,但是1旦2个页面是刚刚注册了service worker,那么它那3回不会被接管,到下2回加载页面包车型地铁时候,service worker才会生效。

当service worker接管了页面之后,它恐怕有二种情形:要么被结束以节约内存,要么会管理fetch和message事件,那八个事件分别发生于二个互连网请求现身依然页面上发送了二个音信。

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

澳门新萄京官方网站 11

二. Service Worker的支撑意况

Service Worker这段时间只有Chrome/Firfox/Opera帮助:

澳门新萄京官方网站 12

Safari和艾德ge也在预备帮助Service Worker,由于ServiceWorker是谷歌(Google)为主的一项正式,对于生态相比较封闭的Safari来讲也是迫于时局开头准备援助了,在Safari TP版本,能够看到:

澳门新萄京官方网站 13

在尝试成效(Experimental Features)里早已有ServiceWorker的菜单项了,只是尽管展开也是不能用,会提醒您还尚未落到实处:

澳门新萄京官方网站 14

但无论是怎么,至少评释Safari已经策动援助ServiceWorker了。此外还足以观望在当年20一七年八月公布的Safari 1一.0.1版本已经协助WebRTC了,所以Safari如故八个前进的男女。

艾德ge也计划扶助,所以Service Worker的前景10分美好。

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

任选壹种支付形式

澳门新萄京官方网站 15 澳门新萄京官方网站 16

1 赞 3 收藏 1 评论

加紧/离线原理探究

打赏接济作者翻译越来越多好作品,感谢!

澳门新萄京官方网站 17

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打探最好实行。

3. 使用Service Worker

ServiceWorker的行使套路是首先登场记三个Worker,然后后台就能运维一条线程,能够在那条线程运行的时候去加载一些财富缓存起来,然后监听fetch事件,在那一个事件里拦截页面包车型客车伸手,先看下缓存里有没有,假如有平素回到,不然平常加载。可能是1开首不缓存,每一种能源请求后再拷贝一份缓存起来,然后下1遍呼吁的时候缓存里就有了。

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

澳门新萄京官方网站 18

前端,在路上... 个人主页 · 作者的篇章 · 19 ·     

澳门新萄京官方网站 19

什么是 Service worker

澳门新萄京官方网站 20

如上图,Service worker 是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当三个页面注册了一个 Service worker,它就足以挂号一名目繁多事件处理器来响应如互连网请求和新闻推送那几个事件。Service worker 能够被用来管理缓存,当响应二个互连网请求时方可陈设为回到缓存依旧从互联网获得。由于Service worker 是依照事件的,所以它只在拍卖那个事件的时候被调入内部存款和储蓄器,不用担心常驻内部存款和储蓄器占用财富导致系统变慢。

有关笔者:Erucy

澳门新萄京官方网站 21

已经的SharePoint喵星程序员(暂且还挂着微软MVP的名头),今后的Azure/.Net/MongoDB/Cordova/前端工程师,有的时候写小说 个人主页 · 作者的小说 · 46 ·   

澳门新萄京官方网站 22

使用Service Worker

前几日大家有了polyfill,并且化解了HTTPS,让大家看看终归怎么用service worker。

(一)注册3个Service Worker

Service Worker对象是在window.navigator里面,如下代码:

JavaScript

window.addEventListener("load", function() { console.log("Will the service worker register?"); navigator.serviceWorker.register('/sw-3.js') .then(function(reg){ console.log("Yes, it did."); }).catch(function(err) { console.log("No it didn't. This happened: ", err) }); });

1
2
3
4
5
6
7
8
9
window.addEventListener("load", function() {
    console.log("Will the service worker register?");
    navigator.serviceWorker.register('/sw-3.js')
    .then(function(reg){
        console.log("Yes, it did.");
    }).catch(function(err) {
        console.log("No it didn't. This happened: ", err)
    });
});

在页面load完之后注册,注册的时候传一个js文件给它,那个js文件正是ServiceWorker的运作条件,假设不能够打响注册的话就能够抛非凡,如Safari TP即使有那么些指标,不过会抛十分没办法利用,就足以在catch里面处理。这里有个难点是怎么供给在load事件运行呢?因为您要十三分运维三个线程,运维未来你恐怕还会让它去加载财富,这一个都以亟需占用CPU和带宽的,我们相应保险页面能平常加载完,然后再起步大家的后台线程,不可能与常规的页面加载发生竞争,那几个在低级移动器具意义比十分大。

再有少数亟待小心的是ServiceWorker和Cookie同样是有帕特h路线的概念的,假如您设定一个cookie要是叫time的path=/page/A,在/page/B那么些页面是不能赢得到这一个cookie的,假如设置cookie的path为根目录/,则持有页面都能获得到。类似地,假诺注册的时候利用的js路径为/page/sw.js,那么这么些ServiceWorker只好管理/page路线下的页面和财富,而不可见管理/api路线下的,所以一般把ServiceWorker注册到一级目录,如上边代码的”/sw-三.js”,那样这一个ServiceWorker就能够接管页面包车型地铁持有财富了。

Service worker生命周期

澳门新萄京官方网站 23

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

澳门新萄京官方网站 24

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

您会开采这几个效果可以很便利地在二个模拟窗口中测试你的service worker,那样您能够关闭和再次张开它,而不会影响到您的新窗口。任何创造在模拟窗口中的注册服务和缓存在窗口被关闭时都将一无往返。

(贰)Service Worker安装和激活

登记完以往,ServiceWorker就能够进展设置,这年会触发install事件,在install事件之中可以缓存一些财富,如下sw-3.js:

JavaScript

const CACHE_NAME = "fed-cache"; this.add伊芙ntListener("install", function(event) { this.skipWaiting(); console.log("install service worker"); // 创制和开发一个缓存库 caches.open(CACHE_NAME); // 首页 let cacheResources = ["]; event.waitUntil( // 请求能源并增加到缓存里面去 caches.open(CACHE_NAME).then(cache => { cache.addAll(cacheResources); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const CACHE_NAME = "fed-cache";
this.addEventListener("install", function(event) {
    this.skipWaiting();
    console.log("install service worker");
    // 创建和打开一个缓存库
    caches.open(CACHE_NAME);
    // 首页
    let cacheResources = ["https://fed.renren.com/?launcher=true"];
    event.waitUntil(
        // 请求资源并添加到缓存里面去
        caches.open(CACHE_NAME).then(cache => {
            cache.addAll(cacheResources);
        })
    );
});

透过上面的操作,创立和加多了二个缓存库叫fed-cache,如下Chrome调整台所示:

澳门新萄京官方网站 25

ServiceWorker的API基本上都是回来Promise对象防止堵塞,所以要用Promise的写法。上面在装置ServiceWorker的时候就把首页的请求给缓存起来了。在ServiceWorker的周转条件之中它有三个caches的全局对象,那一个是缓存的进口,还有一个常用的clients的大局对象,二个client对应七个标签页。

在ServiceWorker里面可以应用fetch等API,它和DOM是割裂的,未有windows/document对象,不可能直接操作DOM,不能直接和页面交互,在ServiceWorker里面不能够得知当前页面张开了、当前页面包车型大巴url是何等,因为五个ServiceWorker管理当前张开的几个标签页,能够经过clients知道全部页面包车型地铁url。还有能够透过postMessage的法门和主页面相互传送音信和数码,进而做些调节。

install完之后,就能够触发Service Worker的active事件:

JavaScript

this.addEventListener("active", function(event) { console.log("service worker is active"); });

1
2
3
this.addEventListener("active", function(event) {
    console.log("service worker is active");
});

ServiceWorker激活之后就可见监听fetch事件了,大家希望每得到三个能源就把它缓存起来,就毫无像上一篇涉嫌的Manifest供给先生成三个列表。

你大概会问,当自个儿刷新页面包车型客车时候不是又重新挂号安装和激活了一个瑟维斯Worker?即便又调了三回注册,但并不会再一次注册,它发掘”sw-三.js”那几个早已登记了,就不会再登记了,进而不会触发install和active事件,因为近些日子瑟维斯Worker已经是active状态了。当须要更新ServiceWorker时,如产生”sw-肆.js”,或许转移sw-叁.js的文书内容,就能再一次登记,新的ServiceWorker会先install然后进入waiting状态,等到重启浏览器时,老的ServiceWorker就能被沟通掉,新的ServiceWorker进入active状态,纵然不想等到再也开动浏览器能够像下边同样在install里面调skipWaiting:

JavaScript

this.skipWaiting();

1
this.skipWaiting();

Service worker的主宰从第一遍页面访问开头

在第3次加载页面时,全部能源都是从网络载的,Service worker 在第三回加载时不会获得调控网络响应,它只会在后续访问页面时起效能。

澳门新萄京官方网站 26

页面第三遍加载时产生install,并跻身idle状态。

澳门新萄京官方网站 27

页面第三次加载时,进入activated状态,盘算管理全体的轩然大波,同时 浏览器会向服务器发送二个异步 请求来检查Service worker自己是或不是有新的本子,构成了Service worker的翻新机制。

澳门新萄京官方网站 28

Service worker管理完全体的风云后,进入idle状态,最终进入terminated状态能源被放飞,当有新的轩然大波发生时再次被调用。

Service Worker的设置步骤

在页面上做到注册手续之后,让咱们把专注力转到service worker的剧本里来,在那中间,大家要成功它的装置步骤。

在最主旨的例证中,你须要为install事件定义3个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个缓存
  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获得3个promise并运用它来获得安装费用的时间以及是或不是安装成功。

假定具有的文件都被缓存成功了,那么service worker就设置成功了。假如此外一个文书下载退步,那么安装步骤就能够破产。这几个格局允许你依附于你和睦钦定的具有能源,但是那代表你须求足够担惊受怕地操纵怎么样文件供给在安装步骤中被缓存。钦定了太多的文书的话,就能够追加设置战败率。

地点只是1个简易的例证,你能够在install事件中实施别的操作依然乃至忽视install事件。

(3)fetch资源后cache起来

如下代码,监听fetch事件做些管理:

JavaScript

this.addEventListener("fetch", function(event) { event.respondWith( caches.match(event.request).then(response => { // cache hit if (response) { return response; } return util.fetchPut(event.request.clone()); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
this.addEventListener("fetch", function(event) {
    event.respondWith(
        caches.match(event.request).then(response => {
            // cache hit
            if (response) {
                return response;
            }
            return util.fetchPut(event.request.clone());
        })
    );
});

先调caches.match看一下缓存里面是还是不是有了,即使有平昔回到缓存里的response,不然的话平常请求能源并把它内置cache里面。放在缓存里能源的key值是Request对象,在match的时候,要求请求的url和header都一模一样才是同样的能源,能够设定第一个参数ignoreVary:

JavaScript

caches.match(event.request, {ignoreVary: true})

1
caches.match(event.request, {ignoreVary: true})

意味着只要请求url一样就认为是同三个财富。

下边代码的util.fetchPut是那样完毕的:

JavaScript

let util = { fetchPut: function (request, callback) { return fetch(request).then(response => { // 跨域的能源直接return if (!response || response.status !== 200 || response.type !== "basic") { return response; } util.putCache(request, response.clone()); typeof callback === "function" && callback(); return response; }); }, putCache: function (request, resource) { // 后台不要缓存,preview链接也并非缓存 if (request.method === "GET" && request.url.indexOf("wp-admin") < 0 && request.url.indexOf("preview_id") < 0) { caches.open(CACHE_NAME).then(cache => { cache.put(request, resource); }); } } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let util = {
    fetchPut: function (request, callback) {
        return fetch(request).then(response => {
            // 跨域的资源直接return
            if (!response || response.status !== 200 || response.type !== "basic") {
                return response;
            }
            util.putCache(request, response.clone());
            typeof callback === "function" && callback();
            return response;
        });
    },
    putCache: function (request, resource) {
        // 后台不要缓存,preview链接也不要缓存
        if (request.method === "GET" && request.url.indexOf("wp-admin") < 0
              && request.url.indexOf("preview_id") < 0) {
            caches.open(CACHE_NAME).then(cache => {
                cache.put(request, resource);
            });
        }
    }
};

亟需小心的是跨域的能源不能够缓存,response.status会重临0,就算跨域的能源支撑CO汉兰达S,那么能够把request的mod改成cors。假设请求战败了,如40四或然是过期等等的,那么也一向重返response让主页面管理,不然的话表达加载成功,把这么些response克隆二个放到cache里面,然后再再次回到response给主页面线程。注意能缓慢存里的财富一般只可以是GET,通过POST获取的是不可能缓存的,所以要做个决断(当然你也能够手动把request对象的method改成get),还有把部分私有不期望缓存的能源也做个推断。

这么只要用户展开过一回页面,ServiceWorker就设置好了,他刷新页面大概打开第一个页面包车型客车时候就能够把请求的财富1一做缓存,蕴含图片、CSS、JS等,只要缓存里有了不管用户在线或许离线都能够健康访问。那样大家自然会有2个难题,这些缓存空间到底有多大?上1篇大家提到Manifest也总算地方存款和储蓄,PC端的Chrome是伍Mb,其实那一个说法在新本子的Chrome已经不标准了,在Chrome 六1版本能够看看本地存款和储蓄的空间和行使景况:

澳门新萄京官方网站 29

内部Cache Storage是指瑟维斯Worker和Manifest占用的长空尺寸和,上海教室能够见见总的空间尺寸是20GB,大致是unlimited,所以基本上不用操心缓存会不够用。

特点

  • 浏览器

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所处的条件是互相隔断的。

澳门新萄京官方网站 30

  • 尚未浏览页面时也得以运维

收下系统事件,后台运营

  • 事件驱动,须要时运转,没有供给时就结束

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

  • 可升级

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

怎么样缓存和重临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。

假如大家有1个命中的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. 丰裕1个callback到fetch请求的 .then 方法中
  2. 要是大家赢得了五个response,大家举行如下的反省:
    1. 保障response是卓有成效的
    2. 自己商讨response的景观是或不是是200
    3. 保障response的档次是basic,那象征请求作者是同源的,非同源(即跨域)的呼吁也不能够被缓存。
  3. 万1大家经过了检查,clone本条请求。这么做的缘由是借使response是一个Stream,那么它的body只可以被读取一遍,所以大家得将它克隆出来,一份发给浏览器,一份发给缓存。

(4)cache html

地方第(三)步把图纸、js、css缓存起来了,不过1旦把页面html也缓存了,举例把首页缓存了,就会有1个尴尬的标题——ServiceWorker是在页面注册的,然方今后获得页面的时候是从缓存取的,每一次都以同等的,所以就导致不可能革新瑟维斯Worker,如变成sw-伍.js,可是PWA又必要大家能缓存页面html。那如何做呢?谷歌(谷歌)的开采者文书档案它只是提到会存在这几个主题素材,但并不曾表明怎么化解这些难点。那几个的难点的缓解将须要我们要有二个体制能掌握html更新了,从而把缓存里的html给替换掉。

Manifest更新缓存的建制是去看Manifest的文本内容有没有爆发变化,假若爆发变化了,则会去创新缓存,ServiceWorker也是依据sw.js的文件内容有未有产生变化,大家得以借鉴那几个思索,借使请求的是html并从缓存里抽取来后,再发个请求获取二个文件看html更新时间是不是发生变化,如若发生变化了则申明爆发退换了,进而把缓存给删了。所以能够在服务端通过垄断(monopoly)这几个文件从而去立异客户端的缓存。如下代码:

JavaScript

this.add伊芙ntListener("fetch", function(event) { event.respondWith( caches.match(event.request).then(response => { // cache hit if (response) { //假若取的是html,则看发个请求看html是或不是更新了 if (response.headers.get("Content-Type").indexOf("text/html") >= 0) { console.log("update html"); let url = new U奇骏L(event.request.url); util.updateHtmlPage(url, event.request.clone(), event.clientId); } return response; } return util.fetchPut(event.request.clone()); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
this.addEventListener("fetch", function(event) {
 
    event.respondWith(
        caches.match(event.request).then(response => {
            // cache hit
            if (response) {
                //如果取的是html,则看发个请求看html是否更新了
                if (response.headers.get("Content-Type").indexOf("text/html") >= 0) {
                    console.log("update html");
                    let url = new URL(event.request.url);
                    util.updateHtmlPage(url, event.request.clone(), event.clientId);
                }
                return response;
            }
 
            return util.fetchPut(event.request.clone());
        })
    );
});

透过响应头header的content-type是或不是为text/html,假使是的话就去发个请求获取三个文书,依照这些文件的剧情决定是或不是供给删除缓存,那几个立异的函数util.updateHtmlPage是如此完成的:

JavaScript

let pageUpdateTime = { }; let util = { updateHtmlPage: function (url, htmlRequest) { let pageName = util.getPageName(url); let jsonRequest = new Request("/html/service-worker/cache-json/" pageName ".sw.json"); fetch(jsonRequest).then(response => { response.json().then(content => { if (pageUpdateTime[pageName] !== content.updateTime) { console.log("update page html"); // 若是有更新则另行赢得html util.fetchPut(htmlRequest); pageUpdateTime[pageName] = content.updateTime; } }); }); }, delCache: function (url) { caches.open(CACHE_NAME).then(cache => { console.log("delete cache "

  • url); cache.delete(url, {ignoreVary: true}); }); } };
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
let pageUpdateTime = {
 
};
let util = {
    updateHtmlPage: function (url, htmlRequest) {
        let pageName = util.getPageName(url);
        let jsonRequest = new Request("/html/service-worker/cache-json/" pageName ".sw.json");
        fetch(jsonRequest).then(response => {
            response.json().then(content => {
                if (pageUpdateTime[pageName] !== content.updateTime) {
                    console.log("update page html");
                    // 如果有更新则重新获取html
                    util.fetchPut(htmlRequest);
                    pageUpdateTime[pageName] = content.updateTime;
                }
            });
        });
    },
    delCache: function (url) {
        caches.open(CACHE_NAME).then(cache => {
            console.log("delete cache " url);
            cache.delete(url, {ignoreVary: true});
        });
    }
};

代码先去赢得三个json文件,三个页面会对应一个json文件,这几个json的内容是那样的:

JavaScript

{"updateTime":"10/2/2017, 3:23:57 PM","resources": {img: [], css: []}}

1
{"updateTime":"10/2/2017, 3:23:57 PM","resources": {img: [], css: []}}

内部主要有二个updateTime的字段,假若地点内部存储器未有那些页面包车型大巴updateTime的数据如故是和流行updateTime不1致,则另行去获得html,然后放到缓存里。接着必要文告页面线程数据产生变化了,你刷新下页面吗。这样就不用等用户刷新页面技巧见效了。所以当刷新完页面后用postMessage文告页面:

JavaScript

let util = { postMessage: async function (msg) { const allClients = await clients.matchAll(); allClients.forEach(client => client.postMessage(msg)); } }; util.fetchPut(htmlRequest, false, function() { util.postMessage({type: 1, desc: "html found updated", url: url.href}); });

1
2
3
4
5
6
7
8
9
let util = {
    postMessage: async function (msg) {
        const allClients = await clients.matchAll();
        allClients.forEach(client => client.postMessage(msg));
    }
};
util.fetchPut(htmlRequest, false, function() {
    util.postMessage({type: 1, desc: "html found updated", url: url.href});
});

并显著type: 一就意味着那是三个创新html的音讯,然后在页面监听message事件:

JavaScript

if("serviceWorker" in navigator) { navigator.serviceWorker.addEventListener("message", function(event) { let msg = event.data; if (msg.type === 1 && window.location.href === msg.url) { console.log("recv from service worker", event.data); window.location.reload(); } }); }

1
2
3
4
5
6
7
8
9
if("serviceWorker" in navigator) {
    navigator.serviceWorker.addEventListener("message", function(event) {
        let msg = event.data;
        if (msg.type === 1 && window.location.href === msg.url) {
            console.log("recv from service worker", event.data);
            window.location.reload();
        }  
    });
}

接下来当大家必要立异html的时候就更新json文件,那样用户就会见到最新的页面了。可能是当用户重新开动浏览器的时候会导致瑟维斯Worker的运营内部存款和储蓄器都被清空了,即存款和储蓄页面更新时间的变量被清空了,那一年也会再一次请求页面。

须要小心的是,要把这么些json文件的http cache时间设置成0,那样浏览器就不会缓存了,如下nginx的布署:

JavaScript

location ~* .sw.json$ { expires 0; }

1
2
3
location ~* .sw.json$ {
    expires 0;
}

因为这么些文件是索要实时获取的,不能够被缓存,firefox暗许会缓存,Chrome不会,加上http缓存时间为0,firefox也不会缓存了。

再有一种更新是用户更新的,举例用户发布了评价,必要在页面公告service worker把html缓存删了再也赢得,那是多少个扭转的消息布告:

JavaScript

if ("serviceWorker" in navigator) { document.querySelector(".comment-form").addEventListener("submit", function() { navigator.serviceWorker.controller.postMessage({ type: 1, desc: "remove html cache", url: window.location.href} ); } }); }

1
2
3
4
5
6
7
8
9
10
if ("serviceWorker" in navigator) {
    document.querySelector(".comment-form").addEventListener("submit", function() {
            navigator.serviceWorker.controller.postMessage({
                type: 1,
                desc: "remove html cache",
                url: window.location.href}
            );
        }
    });
}

Service Worker也监听message事件:

JavaScript

const messageProcess = { // 删除html index 1: function (url) { util.delCache(url); } }; let util = { delCache: function (url) { caches.open(CACHE_NAME).then(cache => { console.log("delete cache "

  • url); cache.delete(url, {ignoreVary: true}); }); } }; this.addEventListener("message", function(event) { let msg = event.data; console.log(msg); if (typeof messageProcess[msg.type] === "function") { messageProcess[msg.type](msg.url); } });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const messageProcess = {
    // 删除html index
    1: function (url) {
        util.delCache(url);
    }
};
 
let util = {
    delCache: function (url) {
        caches.open(CACHE_NAME).then(cache => {
            console.log("delete cache " url);
            cache.delete(url, {ignoreVary: true});
        });
    }
};
 
this.addEventListener("message", function(event) {
    let msg = event.data;
    console.log(msg);
    if (typeof messageProcess[msg.type] === "function") {
        messageProcess[msg.type](msg.url);
    }
});

依据差异的音讯类型调不一样的回调函数,假若是1的话正是删除cache。用户发布完钻探后会触发刷新页面,刷新的时候缓存已经被删了就能够再度去央浼了。

诸如此类就解决了实时更新的难题。

兑现加速/离线

哪些翻新一个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中实行1个管理cache的操作。因为您会供给免去掉在此以前旧的多寡。大家在activate而不是install的时候实行这一个操作是因为若是大家在install的时候马上推行它,那么还是在运维的旧版本的数目就坏了。

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

4. Http/Manifest/Service Worker三种cache的关系

要缓存能够利用两种花招,使用Http Cache设置缓存时间,也得以用Manifest的Application Cache,还足以用ServiceWorker缓存,假设叁者都用上了会怎样呢?

会以Service Worker为预先,因为ServiceWorker把请求拦截了,它早先做管理,尽管它缓存Curry有个别话平素重返,没有的话正常请求,就一定于尚未ServiceWorker了,那个时候就到了Manifest层,Manifest缓存里假使部分话就取那些缓存,要是未有的话就一定于尚未Manifest了,于是就能够从Http缓存里取了,假设Http缓存里也未曾就能够发请求去获取,服务端依据Http的etag可能Modified 提姆e恐怕会重回30四 Not Modified,不然平常重临200和数据内容。那正是整七个到手的进度。

于是只要既用了Manifest又用ServiceWorker的话应该会导致同三个能源存了一回。可是足以让援救ServiceWorker的浏览器选取瑟维斯 Worker,而不辅助的行使Manifest.

Cache

网页缓存有众多,如HTTP缓存,localStorage,sessionStorage和cacheStorage都能够灵活搭配举行缓存,但操作太繁琐,直接行使更加高等Service worker –本文的主人。

拍卖边界和填坑

那1节内容比较新,有多数待定细节。希望那壹节十分的快就无需讲了(因为标准会管理那些难点——译者注),可是未来,那些剧情仍旧应当被提一下。

5. 行使Web App Manifest增加桌面入口

专注这里说的是其它一个Manifest,这一个Manifest是2个json文件,用来放网址icon名称等音信以便在桌面增多1个Logo,以及创造1种张开这些网页仿佛张开App同样的效用。上面平昔说的Manifest是被撤除的Application Cache的Manifest。

本条Maifest.json文件能够这么写:

JavaScript

{ "short_name": "人人FED", "name": "人人网FED,专注于前者本领", "icons": [ { "src": "/html/app-manifest/logo_48.png", "type": "image/png", "sizes": "48x48" }, { "src": "/html/app-manifest/logo_96.png", "type": "image/png", "sizes": "96x96" }, { "src": "/html/app-manifest/logo_192.png", "type": "image/png", "sizes": "192x192" }, { "src": "/html/app-manifest/logo_512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": "/?launcher=true", "display": "standalone", "background_color": "#287fc5", "theme_color": "#fff" }

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
{
  "short_name": "人人FED",
  "name": "人人网FED,专注于前端技术",
  "icons": [
    {
      "src": "/html/app-manifest/logo_48.png",
      "type": "image/png",
      "sizes": "48x48"
    },
    {
      "src": "/html/app-manifest/logo_96.png",
      "type": "image/png",
      "sizes": "96x96"
    },
    {
      "src": "/html/app-manifest/logo_192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/html/app-manifest/logo_512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "/?launcher=true",
  "display": "standalone",
  "background_color": "#287fc5",
  "theme_color": "#fff"
}

icon须求有备无患多样规则,最大须求512px * 512px的,那样Chrome会自动去挑选合适的图纸。要是把display改成standalone,从扭转的Logo展开就能像展开一个App同样,未有浏览器地址栏那个东西了。start_url内定张开未来的输入链接。

然后增加一个link标签指向这么些manifest文件:

JavaScript

<link rel="manifest" href="/html/app-manifest/manifest.json">

1
<link rel="manifest" href="/html/app-manifest/manifest.json">

诸如此类组合Service Worker缓存:
澳门新萄京官方网站 31把start_url指向的页面用ServiceWorker缓存起来,那样当用户用Chrome浏览器张开这么些网页的时候,Chrome就能够在底层弹叁个提醒,询问用户是不是把那么些网页加多到桌面,倘使点“增添”就能够变动3个桌面Logo,从这一个Logo点进去就好像展开三个App同样。感受如下:

澳门新萄京官方网站 32

正如为难的是Manifest近日唯有Chrome帮助,并且只幸好安卓系统上行使,IOS的浏览器非常小概增加贰个桌面Logo,因为IOS未有开放这种API,可是自己的Safari却又是能够的。

综上,本文介绍了怎么用瑟维斯 Worker结合Manifest做二个PWA离线Web APP,主若是用ServiceWorker调控缓存,由于是写JS,比较灵活,还能够与页面举办通讯,另外通过请求页面包车型客车换代时间来决断是不是须求更新html缓存。ServiceWorker的包容性不是特意好,可是前景相比较光明,浏览器都在预备帮忙。现阶段得以组成offline cache的Manifest做离线应用。

连带阅读:

  1. 怎么要把网站升级到HTTPS
  2. 如何把网址进级到http/二
  3. 自家是怎么样让网址用上HTML伍Manifest

1 赞 1 收藏 评论

澳门新萄京官方网站 33

添加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'
})

这么设计是有理由的,它比XHEvoque的在同源下默许发送凭据,但跨域时放弃凭据的规则要来得好。fetch的一颦一笑更像其余的CO普拉多S请求,比如<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

fetch

JavaScript

//////// // Fetch //////// function onFetch(event) { const request = event.request; if (shouldAlwaysFetch(request)) { event.respondWith(networkedOrOffline(request)); return; } if (shouldFetchAndCache(request)) { event.respondWith(networkedOrCached(request)); return; } event.respondWith(cachedOrNetworked(request)); } onFetch做为浏览器互联网请求的代办,依据要求重返互联网或缓存内容,要是获得了网络内容,再次回到互连网请求时同时张开缓存操作。

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

Non-CO宝马X3S默许不辅助

暗中认可景况下,从第二方U奥迪Q7L跨域获得1个能源将会倒闭,除非对方协助了CO猎豹CS6S。你能够增多3个non-COLacrosseS选项到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. 安装单1的high-res版本图片

正如好的方案是二或三,因为1旦把富有的图片都给下载下来存着有一点浪费内存。

假诺你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互连网上下载high-res的本子,不过1旦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" />

若果大家在3个二x的来得形式下,浏览器会下载image-2x.png,假使我们离线,你能够读取此前缓存并回到image-src.png代替,借使在此之前它已经被缓存过。尽管如此,由于后日的情势是二x,浏览器会把400X400的图片展现成200X200,要幸免那个主题材料将要在图纸的体裁上安装宽高。

JavaScript

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

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

澳门新萄京官方网站 34

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

一定网址

  1. Google Chrome

Developer Tools->Application->Service Workers

澳门新萄京官方网站 35

在那边还有四个十三分实用的复选框:

  • Offline

萧规曹随断网状态

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

唯有在Settings里有二个得以在HTTP意况中央银行使Service worker的选项,适应于调节和测试,未有单独网址下的Service worker管理。

澳门新萄京官方网站 36

  1. Opera及其余双核浏览器同谷歌(Google) Chrome
    要是见到三个一样范围内的多少个Service worker,说明Service woker更新后,而原有Service worker还尚无被terminated。

改变URL Hash的Bug

在M40版本中设有2个bug,它会让页面在退换hash的时候产生service worker甘休职业。

你能够在那边找到更加的多相关的消息: 

浏览器全局

探望你的浏览器里都有啥样Service worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

可以观看已经有二四个Serviceworker了,在此处能够手动Start让它专门的工作,也足以Unregister卸载掉。

澳门新萄京官方网站 37

  1. Firefox

有二种办法进入Service worker治本分界面来手动Start或unregister。

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

JavaScript

about:debugging#workers

1
about:debugging#workers

澳门新萄京官方网站 38

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

越多内容

此地有一部分荣辱与共的文书档案能够参谋:

更多

TODO:

  • Service workers的立异须求手动编辑version,每趟发布新小说时索要编写制定。
  • 使用AMP让页面渲染速度直达最高。

获得扶持

假如您遇见麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于我们当下跟进和尽大概援助您化解难点。

赞 2 收藏 评论

澳门新萄京官方网站 39

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

澳门新萄京官方网站 40

本文由澳门新萄京官方网站发布于澳门新萄京赌场网址,转载请注明出处:澳门新萄京官方网站大不列颠及苏格兰联合王国

关键词: