澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

澳门新浦京娱乐场网站:离线网页应用,离线访

利用 Service worker 成立2个非常轻巧的离线页面

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

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

让大家想像以下情况:我们那儿在一辆通往农村的列车的里面,用移动设备望着一篇很棒的篇章。与此同时,当您点击“查看越多”的链接时,高铁忽然进入了隧道,导致移动道具失去了网络,而 web 页面会突显出类似以下的故事情节:

澳门新浦京娱乐场网站 1

那是一定令人消沉的经验!幸运的是,web 开垦者们能透过一些新特色来改正那类的用户体验。作者近年径直在折腾 ServiceWorkers,它给 web 带来的不计其数恐怕性总能给本身欣喜。Service Workers 的爱不忍释特质之1是允许你检查评定网络请求的风貌,并让您作出相应的响应。

在那篇文章里,笔者筹算用此特性检查用户的当前互连网连接处境,假若没连接则赶回一个至上轻便的离线页面。纵然那是3个特别基础的案例,但它能给您带来启迪,让你掌握运维并运维该天性是多么的回顾!假设您没理解过 Service Worker,小编提议你看看此 Github repo,了然越多相关的新闻。

在此案例伊始前,让大家先轻便地看望它的办事流程:

  1. 在用户第一次访问大家的页面时,大家会设置 ServiceWorker,并向浏览器的缓存增多大家的离线 HTML 页面
  2. 下一场,若是用户计划导航到另3个 web 页面(同3个网址下),但此时已断网,那么大家将赶回已被缓存的离线 HTML 页面
  3. 然而,假使用户准备导航到别的2个 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 创设三个自定义的离线页面。

澳门新浦京娱乐场网站 2

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

您正在朝着公司途中的地铁里,在手提式有线电话机上展开了 Guardian 应用。大巴被隧道包围着,但是这几个应用能够平常运营,尽管未有互连网连接,你也能获得完全的效果,除了出示的开始和结果恐怕有一些旧。如若你品尝在网址上也这么干,可惜它完全无法加载:

澳门新浦京娱乐场网站 3

安卓版 Chrome 的离线页面

Chrome 中的这些彩蛋,很四人都不知底》

Chrome 在离线页面上有个藏匿的游艺(桌面版上按空格键,手提式有线电话机版上点击那只恐龙),那有一点点能缓解一点您的烦躁。然而我们得以做得更好。

Service workers 允许网址笔者拦截本身站点的具备互联网请求,那也就表示大家可以提供周详的离线体验,就如原生应用同样。在 Guardian 网站,大家方今上线了三个自定义的离线体验效果。当用户离线的时候,他们会看出八个暗含 Guardian 标记的页面,上边带有三个简便的离线提醒,还有1个填字游戏,他们得以在等候网络连接的时候玩玩这几个找点乐子。那篇博客解释了我们是如何构建它的,但是在始发从前,你能够先自身尝试看。

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('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 时,向缓存增加了离线页面。要是我们将代码分为几小块,可知到前几行代码中,小编为离线页面钦命了缓存版本和UCR-VL。假若您的缓存有分歧版本,那么你只需立异版本号就可以轻松地排除缓存。在大要在第一贰行代码,笔者向这一个离线页面及其财富(如:图片)发出请求。在得到成功的响应后,大家将离线页面和连锁能源丰裕到缓存。

明天,离线页面已存进缓存了,我们可在急需的时等候检查索它。在同一个 瑟维斯Worker 中,大家供给对无网络时重临的离线页面添加相应的逻辑代码。

JavaScript

this.add伊夫ntListener('fetch', event => { // request.mode = navigate isn't supported in all browsers // request.mode = naivgate 并从未拿走全数浏览器的援助 // so include a check for Accept: text/html header. // 因而对 header 的 Accept:text/html 进行核实 if (event.request.mode === 'navigate' || (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) { event.respondWith( fetch(event.request.url).catch(error => { // Return the offline page // 重返离线页面 return caches.match(offlineUrl); }) ); } else{ // Respond with everything else if we can // 重返任何大家能回来的事物 event.respondWith(caches.match(event.request) .then(function (response) { return response || fetch(event.request); }) ); } });

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

为了测试该意义,你能够动用 Chrome 内置的开采者工具。首先,导航到您的页面,然后1旦设置上了 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 相当慢将在帮助了(在每天更新的本子中1度支撑了),除了那么些之外 Safari 之外的享有浏览器也都在搜求。其余,service worker 只好登记在采用了 HTTPS 的网址上,theguardian.com 已经上马逐年搬迁到 HTTPS,所以大家只能在网址的 HTTPS 部分提供离线体验。就当前来讲,大家选拔了 开采者博客 作为大家用来测试的地点。所以一旦你是在我们网址的 开采者博客 部分阅读那篇作品的话,很幸运。

当您利用帮助的浏览器访问大家的 开采者博客 中的页面包车型地铁时候,1切就希图妥帖了。断开你的互连网连接,然后刷新一下页面。假诺你和谐没标准尝试的话,能够看一下这段 示范录像(译者注:需梯子)。

Service Worker 是什么?

五个 service worker 是1段运营在浏览器后台进程里的台本,它独自于这段日子页面,提供了这几个没有须要与web页面交互的功力在网页背后悄悄推行的手艺。在今日,基于它能够兑现消息推送,静默更新以及地理围栏等劳动,不过如今它首先要具有的成效是挡住和管理互连网请求,包罗可编制程序的响应缓存管理。

怎么说这几个API是2个那么些棒的API呢?因为它使得开拓者能够支持相当好的离线体验,它赋予开采者完全调控离线数据的力量。

在service worker提议从前,别的一个提供开拓者离线体验的API叫做App Cache。然则App Cache有些局限性,比方它可以很轻巧地化解单页应用的标题,然而在多页应用上会很辛劳,而Serviceworkers的面世就是为了消除App Cache的痛点。

上面详细说一下service worker有何须求留意的地方:

  • 它是JavaScript Worker,所以它无法直接操作DOM。但是service worker能够经过postMessage与页面之间通讯,把音信文告给页面,假使须要的话,让页面自个儿去操作DOM。
  • Serviceworker是2个可编制程序的互联网代理,允许开垦者调节页面上管理的网络请求。
  • 在不被应用的时候,它会友善终止,而当它再一次被用到的时候,会被再一次激活,所以您无法依附于service worker的onfecth和onmessage的管理函数中的全局状态。假如您想要保存一些长久化的音信,你能够在service worker里使用IndexedDB API。
  • Serviceworker大批量使用promise,所以一旦你不打听怎么着是promise,那您供给先读书这篇文章。

1. 什么是Service Worker

Service Worker是谷歌(谷歌(Google))倡导的贯彻PWA(Progressive Web App)的三个第一剧中人物,PWA是为了消除守旧Web 应用软件的缺点:

(1)未有桌面入口

(2)不可能离线使用

(3)没有Push推送

那Service Worker的具体表现是如何的啊?如下图所示:

澳门新浦京娱乐场网站 8

ServiceWorker是在后台运维的一条服务Worker线程,上海体育地方笔者开了三个标签页,所以体现了七个Client,不过不管开多少个页面都唯有二个Worker在负担处理。这几个Worker的办事是把有些能源缓存起来,然后拦截页面包车型大巴哀求,先看下缓存Curry有未有,借使局地话就从缓存里取,响应200,反之未有的话就走符合规律的呼吁。具体来讲,ServiceWorker结合Web App Manifest能不辱职务以下职业(那也是PWA的检测专门的学问):

澳门新浦京娱乐场网站 9

蕴含可以离线使用、断网时回来200、能唤起用户把网站增加三个Logo到桌面上等。

打开阅读

其它,还有多少个很棒的离线效用案例。如:Guardian 塑造了叁个具有 crossword puzzle(填字游戏)的离线 web 页面 – 因而,纵然等待网络重连时(即已在离线状态下),也能找到一点乐趣。小编也援引看看 Google Chrome Github repo,它包蕴了无数不等的 Service Worker 案例 – 当中某个利用案例也在那!

只是,若是您想跳过上述代码,只是想大致地经过一个库来拍卖相关操作,那么笔者引入您看看 UpUp。这是一个轻量的剧本,能令你更自在地行使离线作用。

打赏辅助笔者翻译越来越多好小说,感激!

打赏译者

增长速度效果

首页加快后,互联网请求从16降为壹,加载时间从2.2玖陆s降为0.654s,得到了一下加载的结果。

澳门新浦京娱乐场网站 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 安装事件的一某个,大家能够动用 新的缓存 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(它是 瑟维斯 Worker API 的1有的)以及 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,你会看到专门为您订制的性子化内容,它们是在你在此之前访问网址时由浏览器缓存下来的。它在装置进程中也不会生出任何不便,你所急需的只是造访那么些网址而已,不像原生应用,还索要用户有2个选用集团的账号技能设置。Serviceworker 一样能够协理我们提高网址的加载速度,因为网址的框架可以被保障地缓存下来,就像是原生应用同样。

假定你对 service worker 很感兴趣,想要驾驭越来越多内容的话,开采者 马特Gaunt(Chrome的忠贞帮忙者)写了1篇特别详细地 介绍 Service Worker的文章。

打赏援助小编翻译越来越多好小说,谢谢!

打赏译者

Service Worker的生命周期

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

要让1个service worker在您的网址上生效,你需求先在你的网页中注册它。注册贰个service worker之后,浏览器会在后台默默运营三个service worker的设置进度。

在设置进程中,浏览器会加载并缓存一些静态财富。要是持有的公文被缓存成功,service worker就安装成功了。如若有其余公文加载或缓存战败,那么安装进度就能退步,service worker就不可能被激活(也即没能安装成功)。固然发生这么的标题,别顾忌,它会在下一次再品尝安装。

澳门新浦京娱乐场网站:离线网页应用,离线访问静态blog网址。当安装到位后,service worker的下一步是激活,在那1阶段,你还是能够升官贰个service worker的版本,具体内容大家会在后头讲到。

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

当service worker接管了页面之后,它也有三种情状:要么被终止以节约内部存款和储蓄器,要么会管理fetch和message事件,那七个事件分别产生于3个互联网请求出现依然页面上发送了一个音讯。

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

澳门新浦京娱乐场网站 11

贰. Service Worker的支撑意况

Service Worker最近只有Chrome/Firfox/Opera援助:

澳门新浦京娱乐场网站 12

Safari和Edge也在预备协理Service Worker,由于ServiceWorker是谷歌(谷歌)主题的1项专门的学业,对于生态比较封闭的Safari来讲也是迫于时势起初企图帮忙了,在Safari TP版本,能够见到:

澳门新浦京娱乐场网站 13

在尝试功用(Experimental Features)里早已有ServiceWorker的菜单项了,只是纵然张开也是不能够用,会唤醒您还尚未兑现:

澳门新浦京娱乐场网站 14

但不管什么,至少表明Safari已经筹算支持ServiceWorker了。此外还足以看看在二零一9年2017年7月揭橥的Safari 1一.0.1版本已经支撑WebRTC了,所以Safari依旧一个进步的男女。

艾德ge也企图辅助,所以Service Worker的前景特别美好。

打赏协助自身翻译越多好文章,多谢!

任选1种支付格局

澳门新浦京娱乐场网站 15 澳门新浦京娱乐场网站 16

1 赞 3 收藏 1 评论

增长速度/离线原理探究

打赏补助笔者翻译更加多好文章,谢谢!

澳门新浦京娱乐场网站 17

1 赞 收藏 澳门新浦京娱乐场网站:离线网页应用,离线访问静态blog网址。 评论

在我们伊始写码此前

从这个种类地址拿到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事件,在这么些事件里拦截页面包车型客车央浼,先看下缓存里有未有,就算有一贯回到,不然符合规律加载。大概是壹起头不缓存,每一种财富请求后再拷贝一份缓存起来,然后下三回呼吁的时候缓存里就有了。

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

澳门新浦京娱乐场网站 18

前端,在路上... 个人主页 · 小编的稿子 · 19 ·     

澳门新浦京娱乐场网站 19

什么是 Service worker

澳门新浦京娱乐场网站 20

如上图,Service worker 是1种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当三个页面注册了三个 Service worker,它就能够注册一文山会海事件管理器来响应如网络请求和消息推送那么些事件。Service worker 能够被用来保管缓存,当响应1个网络请求时得以配备为回去缓存还是从互连网获得。由于Service worker 是基于事件的,所以它只在拍卖这么些事件的时候被调入内部存款和储蓄器,不用忧郁常驻内部存款和储蓄器占用能源导致系统变慢。

关于笔者:Erucy

澳门新浦京娱乐场网站 21

业已的SharePoint喵星技师(一时半刻还挂着微软MVP的名头),今后的Azure/.Net/MongoDB/Cordova/前端程序猿,有的时候写随笔 个人主页 · 小编的稿子 · 46 ·  澳门新浦京娱乐场网站, 

澳门新浦京娱乐场网站 22

使用Service Worker

现行我们有了polyfill,并且解决了HTTPS,让咱们看看终究怎么用service worker。

(一)注册一个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事件运维呢?因为您要特出运营3个线程,运维今后你只怕还会让它去加载能源,这么些都是索要占用CPU和带宽的,大家理应保险页面能健康加载完,然后再起步大家的后台线程,不能够与寻常的页面加载发生竞争,这些在低档移动道具意义十分的大。

还有某个内需专注的是ServiceWorker和Cookie同样是有帕特h路线的定义的,倘令你设定五个cookie假如叫time的path=/page/A,在/page/B这一个页面是不可见拿走到那个cookie的,若是设置cookie的path为根目录/,则兼具页面都能收获到。类似地,若是注册的时候使用的js路线为/page/sw.js,那么那几个ServiceWorker只可以管理/page路线下的页面和能源,而不可能管理/api路线下的,所以一般把ServiceWorker注册到5星级目录,如下边代码的”/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就好像2个智能缓存系统,加强了网络和缓存功效,选用最优办法来响应互连网请求,让使用更加的平稳的运转,尽管未有网络也没涉及,因为你能够完全调整互连网响应。

何以注册和装置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 被注册。

万1那些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第贰版被达成的时候,你也得以在chrome://serviceworker-internals中查看,它很有用,通过它可以最直观地熟悉service worker的生命周期,不过这个功能很快就会被移到chrome://inspect/#service-workers中。

您会意识那一个作用能够很有利地在多个模拟窗口中测试你的service worker,那样您能够关闭和再一次张开它,而不会影响到你的新窗口。任何创立在模拟窗口中的注册服务和缓存在窗口被关闭时都将一去不返。

(二)Service Worker安装和激活

注册完事后,ServiceWorker就能够进展设置,这年会触发install事件,在install事件之中能够缓存一些财富,如下sw-三.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);
        })
    );
});

透过地方的操作,创立和增加了3个缓存库叫fed-cache,如下Chrome调整台所示:

澳门新浦京娱乐场网站 25

瑟维斯Worker的API基本上都以回来Promise对象幸免堵塞,所以要用Promise的写法。上边在设置ServiceWorker的时候就把首页的伸手给缓存起来了。在ServiceWorker的运营情形之中它有三个caches的大局对象,那个是缓存的入口,还有一个常用的clients的全局对象,3个client对应二个标签页。

在ServiceWorker里面可以应用fetch等API,它和DOM是与世隔膜的,未有windows/document对象,无法直接操作DOM,无法直接和页面交互,在瑟维斯Worker里面不或然获知当前页面张开了、当前页面包车型客车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事件了,大家希望每得到二个财富就把它缓存起来,就毫无像上1篇涉嫌的Manifest供给先生成3个列表。

你或然会问,当自家刷新页面包车型大巴时候不是又再次登记安装和激活了三个ServiceWorker?纵然又调了1回注册,但并不会再次注册,它开掘”sw-3.js”那些早已登记了,就不会再登记了,进而不会触发install和active事件,因为日前ServiceWorker已经是active状态了。当必要革新ServiceWorker时,如造成”sw-四.js”,可能转移sw-三.js的文件内容,就能再一次登记,新的ServiceWorker会先install然后进入waiting状态,等到重启浏览器时,老的ServiceWorker就能够被调换掉,新的ServiceWorker进入active状态,假设不想等到再也开动浏览器能够像上边一样在install里面调skipWaiting:

JavaScript

this.skipWaiting();

1
this.skipWaiting();

瑟维斯 worker的调控从第一回页面访问开头

在首次加载页面时,全部能源都以从互联网载的,Service worker 在第一遍加载时不会赢得调整网络响应,它只会在继续访问页面时起效果。

澳门新浦京娱乐场网站 26

页面第三次加载时变成install,并进入idle状态。

澳门新浦京娱乐场网站 27

页面第3遍加载时,进入activated状态,计划管理全数的事件,同时 浏览器会向服务器发送1个异步 请求来检查Service worker小编是不是有新的本子,构成了Service worker的换代机制。

澳门新浦京娱乐场网站 28

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. 开启3个缓存
  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就设置成功了。如若其它一个文本下载退步,那么安装步骤就能够战败。这些点子允许你凭仗于您和煦钦赐的有所资源,可是那意味着你须求特别谨慎地决定怎么样文件要求在装置步骤中被缓存。内定了太多的公文的话,就能大增设置战败率。

地点只是一个简短的例子,你能够在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都平等才是同等的财富,可以设定第3个参数ignoreVary:

JavaScript

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

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

代表1旦请求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,若是跨域的财富支撑COEscortS,那么能够把request的mod改成cors。假设请求失利了,如40四要么是晚点等等的,那么也一贯回到response让主页面管理,不然的话表明加载成功,把那些response克隆贰个内置cache里面,然后再回来response给主页面线程。注意能减缓存里的财富一般只好是GET,通过POST获取的是不可能缓存的,所以要做个推断(当然你也能够手动把request对象的method改成get),还有把壹部分私有不期望缓存的财富也做个推断。

如此只要用户打开过三回页面,ServiceWorker就设置好了,他刷新页面恐怕展开第一个页面包车型大巴时候就能够把请求的财富一1做缓存,包含图片、CSS、JS等,只要缓存里有了不管用户在线或然离线都能够健康访问。那样大家本来会有二个难题,那一个缓存空间到底有多大?上壹篇我们提到Manifest也总算地点存款和储蓄,PC端的Chrome是5Mb,其实这么些说法在新本子的Chrome已经不纯粹了,在Chrome 陆1版本可以见见当地存款和储蓄的上空和采用景况:

澳门新浦京娱乐场网站 29

其中Cache Storage是指ServiceWorker和Manifest占用的长空尺寸和,上海体育地方可以观望总的空间尺寸是20GB,差不多是unlimited,所以基本上不用操心缓存会不够用。

特点

  • 浏览器

谷歌 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里,大家传入了1个由caches.match发生的promise.caches.match 查找request中被service worker缓存命中的response。

若是大家有2个命中的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其1请求。这么做的原故是壹旦response是3个Stream,那么它的body只可以被读取叁次,所以大家得将它克隆出来,1份发给浏览器,一份发给缓存。

(4)cache html

上边第(叁)步把图纸、js、css缓存起来了,不过只要把页面html也缓存了,比方把首页缓存了,就能够有1个啼笑皆非的难点——ServiceWorker是在页面注册的,可是未来获取页面包车型大巴时候是从缓存取的,每便都是一样的,所以就招致力不从心立异ServiceWorker,如产生sw-5.js,不过PWA又须求大家能缓存页面html。那如何做吧?谷歌的开拓者文书档案它只是提到会存在这么些题目,但并从未证实怎么解决那么些主题素材。这一个的主题素材的消除将供给大家要有一个机制能清楚html更新了,从而把缓存里的html给替换掉。

Manifest更新缓存的建制是去看Manifest的文本内容有没有产生变化,要是产生变化了,则会去创新缓存,ServiceWorker也是依赖sw.js的公文内容有未有发生变化,大家能够借鉴这些思索,借使请求的是html并从缓存里收取来后,再发个请求获取3个文书看html更新时间是或不是发生变化,假使产生变化了则表达发生更改了,进而把缓存给删了。所以能够在服务端通过调控这一个文件从而去立异客户端的缓存。如下代码:

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,假若是的话就去发个请求获取2个文件,依照那些文件的内容决定是不是要求删除缓存,那几个创新的函数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文件,多个页面会对应2个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不均等,则再次去取得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: 1就表示那是一个翻新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文件,那样用户就能够看到最新的页面了。或许是当用户重新开动浏览器的时候会导致ServiceWorker的运营内存都被清空了,即存款和储蓄页面更新时间的变量被清空了,这年也会重新请求页面。

急需小心的是,要把这么些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);
    }
});

依赖不相同的音信类型调不一致的回调函数,借使是一的话就是删除cache。用户发表完切磋后会触发刷新页面,刷新的时候缓存已经被删了就能够再也去乞请了。

这么就缓慢解决了实时更新的难题。

完结加速/离线

什么立异2个Service Worker

您的service worker总有亟待立异的那一天。当那一天来到的时候,你需求服从如下步骤来更新:

  1. 立异您的service worker的JavaScript文件
    1. 当用户浏览你的网址,浏览器尝试在后台下载service worker的剧本文件。只要服务器上的文件和当半夏件有1个字节差别,它们就被判断为急需更新。
  2. 创新后的service worker将启幕运作,install event被另行触发。
  3. 在那么些时刻节点上,当前页不熟悉效的如故是老版本的service worker,新的servicer worker将进入”waiting”状态。
  4. 此时此刻页面被关门之后,老的service worker进度被杀死,新的servicer worker正式生效。
  5. 假如新的service worker生效,它的activate事件被触发。

代码更新后,平时须要在activate的callback中举行三个管制cache的操作。因为你会需求消除掉在此以前旧的数码。大家在activate而不是install的时候履行这些操作是因为壹旦咱们在install的时候立即实行它,那么照旧在运维的旧版本的多寡就坏了。

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

上面包车型地铁代码能够循环全体的缓存,删除掉全部不在白名单中的缓存。

JavaScript

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

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

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 Time恐怕会回来30四 Not Modified,不然平常重返200和数码内容。那就是整3个赢得的历程。

之所以借使既用了Manifest又用ServiceWorker的话应该会促成同3个财富存了三次。不过足以让支持ServiceWorker的浏览器选用Service Worker,而不帮助的施用Manifest.

Cache

网页缓存有过多,如HTTP缓存,localStorage,sessionStorage和cacheStorage都能够灵活搭配进行缓存,但操作太繁琐,直接采取更加高档Service worker –本文的庄家。

拍卖边界和填坑

这一节内容相比新,有数不完待定细节。希望那壹节非常的慢就没有需求讲了(因为标准会管理这几个主题素材——译者注),不过现在,这一个情节还是应当被提一下。

5. 应用Web App Manifest增多桌面入口

瞩目这里说的是此外一个Manifest,那一个Manifest是一个json文件,用来放网站icon名称等音信以便在桌面增添二个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必要预备几种准绳,最大须求51二px * 51二px的,那样Chrome会自动去选拔合适的图样。如若把display改成standalone,从变化的Logo张开就可以像张开三个App同样,未有浏览器地址栏这个东西了。start_url指定展开之后的入口链接。

接下来增加1个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就能在尾巴部分弹二个升迁,询问用户是还是不是把这些网页增添到桌面,假设点“增加”就能够转换贰个桌面Logo,从那些Logo点进去就好像张开3个App同样。感受如下:

澳门新浦京娱乐场网站 32

相比难堪的是Manifest近些日子唯有Chrome扶助,并且不得不在安卓系统上运用,IOS的浏览器不大概增加2个桌面图标,因为IOS未有开放这种API,不过自身的Safari却又是足以的。

综上,本文介绍了怎么用Service Worker结合Manifest做三个PWA离线Web 应用软件,首若是用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);
    });

1旦设置退步了,未有很优雅的措施获得通报

假如三个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'
})

诸如此类设计是有理由的,它比XHTiggo的在同源下私下认可发送凭据,但跨域时舍弃凭据的规则要来得好。fetch的行为更像其余的COHummerH二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景逸SUVS暗许不帮助

暗许景况下,从第二方U奥迪Q7L跨域获得三个财富将会失利,除非对方援救了COLANDS。你能够增多1个non-CO途达S选项到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步骤缓存2个图纸,你有以下二种采用:

  1. 安装具备的<picture>元素或者将被请求的srcset属性。
  2. 安装单壹的low-res版本图片
  3. 安装单1的high-res版本图片

正如好的方案是二或三,因为一旦把具有的图片都给下载下来存着有一点浪费内部存款和储蓄器。

设若你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从网络上下载high-res的本子,不过只要high-res版本下载失利以来,就如故用low-res版本。这么些主见很好也值得去做,不过有贰个标题:

若是我们有上面三种图片:

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

HTML代码如下:

JavaScript

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

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

假使我们在3个二x的来得格局下,浏览器会下载image-②x.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;" />

澳门新浦京娱乐场网站 34

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

一定网址

  1. Google Chrome

Developer Tools->Application->Service Workers

澳门新浦京娱乐场网站 35

在此地还有三个要命实惠的复选框:

  • Offline

宪章断网状态

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

除非在Settings里有1个得以在HTTP碰着中利用Service worker的选项,适应于调节和测试,未有单独网址下的Service worker管理。

澳门新浦京娱乐场网站 36

  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/

能够看到已经有2四个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

本文由澳门新浦京娱乐场网站发布于新浦京娱乐场官网,转载请注明出处:澳门新浦京娱乐场网站:离线网页应用,离线访