英帝国卫报的天性离线页面是这么做的,离线网

Service Worker初体验

2016/01/06 · JavaScript · Service Worker

原著出处: AlloyTeam   

在2016年,W3C公布了service worker的草案,service worker提供了过多新的力量,使得web app具有与native app同样的离线体验、新闻推送体验。
service worker是一段脚本,与web worker同样,也是在后台运维。作为叁个单身的线程,运行条件与日常脚本不一致,所以无法直接参与web交互行为。native app能够做到离线使用、音信推送、后台自动更新,service worker的现身是幸亏为了使得web app也得以享有类似的力量。

 

service worker可以:

  1. 后台音讯传递
  2. 互联网代理,转载呼吁,伪造响应
  3. 离线缓存
  4. 新闻推送
  5.  … …

正文以能源缓存为例,说澳优下service worker是何等专门的学业的。

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

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

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

作者们是什么样运用 service worker 来为 theguardian.com 营造一个自定义的离线页面。

图片 1

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

你正在朝着公司途中的大巴里,在小叔子大上展开了 Guardian 应用。大巴被隧道包围着,不过那几个应用能够健康运营,即便未有互联网连接,你也能博取完整的功能,除了显示的内容大概有一点旧。假使您品尝在网址上也这么干,缺憾它完全没办法加载:

图片 2

安卓版 Chrome 的离线页面

Chrome 中的这些彩蛋,相当多个人都不知道》

Chrome 在离线页面上有个暗藏的嬉戏(桌面版上按空格键,手提式有线电电话机版上点击那只恐龙),那某个能缓慢化解一点你的困扰。不过大家得以做得更加好。

Service workers 允许网址我拦截本人站点的保有互联网乞求,那也就象征我们能够提供完善的离线体验,就像原生应用一样。在 Guardian 网址,大家近期上线了二个自定义的离线体验效果。当客商离线的时候,他们会看到一个含有 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博客   

在上一篇《本人是何等让网站用上HTML5 Manifest》介绍了怎么用Manifest做多少个离线网页应用,结果被左近网络朋友吐槽说这几个事物已经被deprecated,移出web标准了,今后被ServiceWorker取代了,不管怎样,Manifest的一部分思考还是能够借用的。小编又将网站升级到了ServiceWorker,假若是用Chrome等浏览器就用ServiceWorker做离线缓存,借使是Safari浏览器就依然用Manifest,读者能够张开那些网址感受一下,断网也是能健康张开。

生命周期

先来看一下多个service worker的运作周期

图片 3
上海体育地方是service worker生命周期,出处

图中能够看来,一个service worker要经历以下进程:

  1.  安装

2.  激活,激活成功未来,展开chrome://inspect/#service-workers能够查阅到近些日子运维的service worker

图片 4

  1. 监听fetch和message事件,下边三种事件会打开简要描述

  2. 销毁,是或不是销毁由浏览器决定,如若贰个service worker长时间不采纳依旧机器内部存款和储蓄器有数,则大概会销毁那么些worker

试试看

您供给多个支撑 Service Worker 和 fetch API 的浏览器。截至到本文编写时只有Chrome(手提式有线电话机版和桌面版)同期扶助那二种 API(译者注:Opera 最近也支撑这两侧),可是 Firefox 一点也不慢就要扶助了(在每一天更新的本子中一度支撑了),除却 Safari 之外的具备浏览器也都在尝试。另外,service worker 只可以登记在动用了 HTTPS 的网址上,theguardian.com 已经最初逐步搬迁到 HTTPS,所以大家只可以在网址的 HTTPS 部分提供离线体验。就现阶段以来,大家挑选了 开采者博客 作为我们用来测量检验的地点。所以假若您是在我们网站的 开垦者博客 部分阅读这篇小说的话,很幸运。

当您使用扶助的浏览器访谈大家的 开拓者博客 中的页面的时候,一切就计划妥贴了。断开你的互连网连接,然后刷新一下页面。若是您自个儿没条件尝试的话,可以看一下这段 以身作则摄像(译者注:需梯子)。

Service Worker 是什么?

贰个 service worker 是一段运维在浏览器后台进程里的剧本,它独自于最近页面,提供了那贰个无需与web页面交互的效果在网页背后悄悄施行的本事。在以往,基于它可以兑现音信推送,静默更新以及地理围栏等劳务,可是最近它首先要具有的意义是掣肘和管理网络央浼,满含可编制程序的响应缓存管理。

何以说这些API是一个不胜棒的API呢?因为它使得开荒者能够支撑非常好的离线体验,它赋予开垦者完全调节离线数据的技术。

在service worker建议从前,别的叁个提供开荒者离线体验的API叫做App Cache。可是App Cache某个局限性,比如它能够很轻巧地消除单页应用的题材,可是在多页应用上会很麻烦,而Serviceworkers的产出正是为了缓慢解决App Cache的痛点。

上边详细说一下service worker有啥样必要留神的地点:

  • 它是JavaScript Worker,所以它无法间接操作DOM。不过service worker能够经过postMessage与页面之间通讯,把消息布告给页面,假如须求的话,让页面自身去操作DOM。
  • Serviceworker是八个可编制程序的网络代理,允许开拓者调整页面上拍卖的网络央求。
  • 在不被应用的时候,它会友善终止,而当它再一次被用到的时候,会被重新激活,所以您不可能依附于service worker的onfecth和onmessage的管理函数中的全局状态。借令你想要保存一些长久化的新闻,你能够在service worker里使用IndexedDB API。
  • Serviceworker大批量使用promise,所以倘令你不打听如何是promise,那你须要先读书这篇文章。

1. 什么是Service Worker

Service Worker是谷歌(Google)倡导的贯彻PWA(Progressive Web App)的七个第一角色,PWA是为了化解守旧Web APP的毛病:

(1)未有桌面入口

(2)不能够离线使用

(3)没有Push推送

那Service Worker的具体展现是什么样的啊?如下图所示:

图片 5

ServiceWorker是在后台启动的一条服务Worker线程,上海教室小编开了多个标签页,所以呈现了五个Client,不过不管开多少个页面都唯有二个Worker在负担管理。这些Worker的办事是把某个能源缓存起来,然后拦截页面包车型地铁呼吁,先看下缓存库里有没有,要是局地话就从缓存里取,响应200,反之未有的话就走符合规律的央浼。具体来讲,ServiceWorker结合Web App Manifest能到位以下职业(那也是PWA的检查实验专门的学问):

图片 6

席卷能够离线使用、断网时回来200、能提示顾客把网站增加一个图标到桌面上等。

fetch事件

在页面发起http央浼时,service worker能够通过fetch事件拦截恳求,并且付诸本身的响应。
w3c提供了一个新的fetch api,用于代替XMLHttpRequest,与XMLHttpRequest最大不一样有两点:

1. fetch()方法再次来到的是Promise对象,通过then方法进行连接调用,收缩嵌套。ES6的Promise在改为专门的学业之后,会越发便利开荒人士。

2. 提供了Request、Response对象,假若做过后端开拓,对Request、Response应该比较熟知。前端要发起呼吁能够经过url发起,也能够应用Request对象发起,何况Request能够复用。不过Response用在哪儿啊?在service worker现身在此之前,前端确实不会协和给和煦发音信,不过有了service worker,就足以在阻止乞请之后据悉要求发回本人的响应,对页面来说,那一个平凡的伸手结果并未区分,那是Response的一处接纳。

下边是在中,小编运用fetch api通过fliker的当众api获取图片的例证,注释中详细解释了每一步的效劳:

JavaScript

/* 由于是get伏乞,直接把参数作为query string传递了 */ var URL = ''; function fetch德姆o() { // fetch(url, option)帮助五个参数,option中得以设置header、body、method音信fetch(ULANDL).then(function(response) { // 通过promise 对象获得对应内容,并且将响应内容遵照json格式转成对象,json()方法调用之后再次回到的还是是promise对象 // 也得以把内容转化成arraybuffer、blob对象 return response.json(); }).then(function(json) { // 渲染页面 insertPhotos(json); }); } fetch德姆o();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 由于是get请求,直接把参数作为query string传递了 */
var URL = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=your_api_key&format=json&nojsoncallback=1&tags=penguins';
 
function fetchDemo() {
  // fetch(url, option)支持两个参数,option中可以设置header、body、method信息
  fetch(URL).then(function(response) {
    // 通过promise 对象获得相应内容,并且将响应内容按照json格式转成对象,json()方法调用之后返回的依然是promise对象
    // 也可以把内容转化成arraybuffer、blob对象
    return response.json();
  }).then(function(json) {
    // 渲染页面
    insertPhotos(json);
  });
}
 
fetchDemo();

fetch api与XMLHttpRequest相比较,特别简洁,並且提供的功用更完美,财富获得方式比ajax更优雅。包容性方面:chrome 42开头支持,对于旧浏览器,能够因此合法维护的polyfill支持。

办事规律

经过一段简单的 JavaScript,我们能够提醒浏览器在客户访谈页面包车型地铁时候立即登记大家和好的 service worker。这几天补助 service worker 的浏览器比很少,所感觉了幸免不当,大家须求利用本性检查实验。

JavaScript

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

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

Service worker 安装事件的一片段,大家得以应用 新的缓存 API 来缓存大家网址中的各样内容,举个例子 HTML、CSS 和 JavaScript:

JavaScript

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

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

当安装到位后,service worker 能够监听和操纵 fetch 事件,让大家能够完全调整之后网址中生出的具备互连网央浼。

JavaScript

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

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

在此间大家有很利索的半空中能够发挥,举个例子下边那么些点子,能够经过代码来生成大家自身的恳求响应:

JavaScript

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

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

还会有那几个,如若在缓存中找到了央浼相应的缓存,大家得以平昔从缓存中回到它,如若没找到的话,再经过网络获取响应内容:

JavaScript

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

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

那么大家怎样利用这个职能来提供离线体验吧?

首先,在 service worker 安装进程中,我们须要把离线页面须要的 HTML 和能源文件通过 service worker 缓存下来。在缓存中,大家加载了友好开支的 填字游戏 的 React应用 页面。之后,大家会阻拦全部访谈theguardian.com 网络央浼,蕴涵网页、以及页面中的财富文件。管理这个诉求的逻辑大约如下:

  1. 当大家检验到传播乞请是指向大家的 HTML 页面时,我们连年会想要提供新型的剧情,所以大家会尝试把这些乞请通过网络发送给服务器。
    1. 当大家从服务器获得了响应,就足以一向回到那个响应。
    2. 设若网络诉求抛出了格外(举个例子因为客商掉线了),大家捕获这些非常,然后使用缓存的离线 HTML 页面作为响应内容。
  2. 要不,当大家检查实验到供给的不是 HTML 的话,大家会从缓存中寻找响应的伏乞内容。
    1. 一旦找到了缓存内容,大家能够直接再次回到缓存的内容。
    2. 要不然,大家会尝试把那些央浼通过网络发送给服务器。

在代码中,大家使用了 新的缓存 API(它是 Service Worker API 的一有些)以及 fetch 功用(用于转移互连网哀告),如下所示:

JavaScript

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var doesRequestAcceptHtml = function (request) {
    return request.headers.get('Accept')
        .split(',')
        .some(function (type) { return type === 'text/html'; });
};
 
self.addEventListener('fetch', function (event) {
    var request = event.request;
    if (doesRequestAcceptHtml(request)) {
        // HTML pages fallback to offline page
        event.respondWith(
            fetch(request)
                .catch(function () {
                    return caches.match('/offline-page.html');
                })
        );
    } else {
        // Default fetch behaviour
        // Cache first for all other requests
        event.respondWith(
            caches.match(request)
                .then(function (response) {
                    return response || fetch(request);
                })
        );
    }
});

就只要求这么多!theguardian.com 上的 富有代码都是在 GitHub 上开源 的,所以您可以去那儿查看我们的 service worker 的完全版本,或然直接从生育遇到上访问 。

咱俩有丰盛的理由为这个新的浏览器技巧欢呼喝彩,因为它能够用来让您的网站像前几日的原生应用一样,具备完善的离线体验。未来当 theguardian.com 完全迁移到 HTTPS 之后,离线页面包车型大巴显要性会显然增多,大家得以提供越来越圆满的离线体验。虚构一下你在上下班路上互联网比比较糟糕的时候访问theguardian.com,你会看出特地为您订制的本性化内容,它们是在你在此以前访谈网址时由浏览器缓存下来的。它在安装进程中也不会发出其余勤奋,你所急需的只是会见这些网址而已,不像原生应用,还须求顾客有一个使用公司的账号能力设置。Serviceworker 同样能够援救我们进步网址的加载速度,因为网址的框架能够被保障地缓存下来,就如原生应用一样。

假诺您对 service worker 很感兴趣,想要精通越多内容的话,开辟者 MattGaunt(Chrome的忠贞协理者)写了一篇特别详实地 介绍 Service Worker的文章。

打赏扶助本人翻译更加多好文章,多谢!

打赏译者

Service Worker的生命周期

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

要让一个service worker在你的网址上生效,你必要先在您的网页中登记它。注册二个service worker之后,浏览器会在后台默默运维贰个service worker的设置进程。

在设置进程中,浏览器会加载并缓存一些静态能源。假若具有的文件被缓存成功,service worker就设置成功了。要是有其余文件加载或缓存失败,那么安装进度就能够停业,service worker就不能够被激活(也即未能安装成功)。假如发生这么的标题,别担忧,它会在下一次再尝试安装。

当安装实现后,service worker的下一步是激活,在这一阶段,你还足以升高叁个service worker的版本,具体内容大家会在后头讲到。

在激活之后,service worker将接管全体在温馨管辖域范围内的页面,可是一旦贰个页面是刚刚注册了service worker,那么它那一遍不会被接管,到下二遍加载页面包车型地铁时候,service worker才会生效。

当service worker接管了页面之后,它恐怕有二种情况:要么被结束以节约内部存款和储蓄器,要么会管理fetch和message事件,那么些事件分别发生于二个互联网诉求出现依旧页面上发送了一个音讯。

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

图片 7

2. Service Worker的支撑处境

Service Worker最近唯有Chrome/Firfox/Opera辅助:

图片 8

Safari和艾德ge也在备选协助Service Worker,由于ServiceWorker是Google宗旨的一项正式,对于生态相比较密闭的Safari来讲也是迫于时局初叶计划支持了,在Safari TP版本,能够观看:

图片 9

在实验成效(Experimental Features)里曾经有ServiceWorker的菜单项了,只是尽管展开也是不能用,会提示您还从未完结:

图片 10

但无论怎么着,至少表明Safari已经计划支持瑟维斯Worker了。别的还是能够看看在当年前年三月颁发的Safari 11.0.1本子现已支撑WebRTC了,所以Safari依然一个进步的孩子。

Edge也策画援救,所以Service Worker的前景非常美好。

message事件

页面和serviceWorker之间能够经过posetMessage()方法发送消息,发送的信息能够因而message事件接收到。

那是三个双向的进程,页面能够发新闻给service worker,service worker也能够发送新闻给页面,由于那性格格,能够将service worker作为中间纽带,使得叁个域名依旧子域名下的多少个页面能够自由通讯。

此地是贰个小的页面之间通讯demo

打赏补助自身翻译更加多好文章,感激!

图片 11

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事件,在那几个事件里拦截页面包车型客车央浼,先看下缓存里有没有,若是有直接再次来到,不然寻常加载。或然是一同先不缓存,每种能源央浼后再拷贝一份缓存起来,然后下三遍呼吁的时候缓存里就有了。

利用service workder缓存文件

上边介绍贰个行使service worker缓存离线文件的事例
有备无患index.js,用于注册service-worker

JavaScript

if (navigator.serviceWorker) { navigator.serviceWorker.register('service-worker.js').then(function(registration) { console.log('service worker 注册成功'); }).catch(function (err) { console.log('servcie worker 注册失败') }); }

1
2
3
4
5
6
7
if (navigator.serviceWorker) {
    navigator.serviceWorker.register('service-worker.js').then(function(registration) {
        console.log('service worker 注册成功');
    }).catch(function (err) {
        console.log('servcie worker 注册失败')
    });
}

在上述代码中,注册了service-worker.js作为当前路径下的service worker。由于service worker的权杖非常高,全数的代码都亟待是安全可靠的,所以唯有https站点本领够行使service worker,当然localhost是叁个特例。
注册甘休,未来开头写service-worker.js代码。
依据后边的生命周期图,在七个新的service worker被注册之后,首先会触发install事件,在service-workder.js中,可以透过监听install事件开展一些最早化职业,可能哪些也不做。
因为大家是要缓存离线文件,所以能够在install事件中初露缓存,可是只是将文件加到caches缓存中,真正想让浏览器接纳缓存文件供给在fetch事件中梗阻

JavaScript

var cacheFiles = [ 'about.js', 'blog.js' ]; self.addEventListener('install', function (evt) { evt.waitUntil( caches.open('my-test-cahce-v1').then(function (cache) { return cache.addAll(cacheFiles); }) ); });

1
2
3
4
5
6
7
8
9
10
11
var cacheFiles = [
    'about.js',
    'blog.js'
];
self.addEventListener('install', function (evt) {
    evt.waitUntil(
        caches.open('my-test-cahce-v1').then(function (cache) {
            return cache.addAll(cacheFiles);
        })
    );
});

第一定义了亟待缓存的公文数组cacheFile,然后在install事件中,缓存那几个文件。
evt是一个Install伊芙nt对象,承接自ExtendableEvent,个中的waitUntil()方法接收叁个promise对象,直到那个promise对象成功resolve之后,才会一而再运维service-worker.js。
caches是三个CacheStorage对象,使用open()方法展开三个缓存,缓存通过名称举办区分。
获得cache实例之后,调用addAll()方法缓存文件。

这般就将文件增添到caches缓存中了,想让浏览器选取缓存,还须要拦截fetch事件

JavaScript

// 缓存图片 self.add伊夫ntListener('fetch', function (evt) { evt.respondWith( caches.match(evt.request).then(function(response) { if (response) { return response; } var request = evt.request.clone(); return fetch(request).then(function (response) { if (!response && response.status !== 200 && !response.headers.get('Content-type').match(/image/)) { return response; } var responseClone = response.clone(); caches.open('my-test-cache-v1').then(function (cache) { cache.put(evt.request, responseClone); }); return response; }); }) ) });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 缓存图片
self.addEventListener('fetch', function (evt) {
    evt.respondWith(
        caches.match(evt.request).then(function(response) {
            if (response) {
                return response;
            }
            var request = evt.request.clone();
            return fetch(request).then(function (response) {
                if (!response && response.status !== 200 && !response.headers.get('Content-type').match(/image/)) {
                    return response;
                }
                var responseClone = response.clone();
                caches.open('my-test-cache-v1').then(function (cache) {
                    cache.put(evt.request, responseClone);
                });
                return response;
            });
        })
    )
});

通过监听fetch事件,service worker能够回来自个儿的响应。

率先检缓存中是或不是曾经缓存了那几个必要,假使有,就径直再次回到响应,就减弱了贰次网络央浼。不然由service workder发起央浼,那时的service workder起到了贰个中等代理的功用。

service worker乞求的进度通过fetch api完结,获得response对象未来实行过滤,查看是还是不是是图片文件,假设不是,就径直回到伏乞,不会缓存。

假借使图表,要先复制一份response,原因是request只怕response对象属于stream,只好采用三次,之后一份存入缓存,另一份发送给页面。
那就是service worker的雄强之处:拦截乞求,伪造响应。fetch api在此处也起到了十分大的成效。

 

service worker的更新很轻易,只要service-worker.js的文书内容有立异,就能够利用新的台本。但是有好几要小心:旧缓存文件的清除、新文件的缓存要在activate事件中进行,因为恐怕旧的页面还在运用此前的缓存文件,清除之后会错失效率。

 

在第一使用service worker的长河中,也遇上了部分标题,上面是里面四个

有关小编:Erucy

图片 12

曾经的SharePoint喵星程序员(临时还挂着微软MVP的名头),未来的Azure/.Net/MongoDB/Cordova/前端程序员,有时写小说 个人主页 · 小编的小说 · 46 ·   

图片 13

使用Service Worker

当今我们有了polyfill,并且化解了HTTPS,让我们看看终归怎么用service worker。

(1)注册多个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和带宽的,大家应当保险页面能健康加载完,然后再起步大家的后台线程,不能与不奇怪的页面加载发生竞争,这几个在低档移动道具意义相当大。

还会有少数索要留心的是瑟维斯Worker和Cookie同样是有Path路线的定义的,假令你设定叁个cookie假使叫time的path=/page/A,在/page/B那些页面是不可见取获得这几个cookie的,假若设置cookie的path为根目录/,则具备页面都能获得到。类似地,假若注册的时候使用的js路径为/page/sw.js,那么那个ServiceWorker只可以管理/page路线下的页面和能源,而无法处理/api路线下的,所以一般把ServiceWorker注册到五星级目录,如上面代码的”/sw-3.js”,那样这一个瑟维斯Worker就会接管页面包车型大巴装有资源了。

主题素材1. 运维时刻

service worker并不是直接在后台运营的。在页面关闭后,浏览器能够三番五次保持service worker运营,也得以关闭service worker,那有赖于与浏览器本人的一言一动。所以不要定义一些全局变量,譬如上面包车型地铁代码(来自):

JavaScript

var hitCounter = 0; this.addEventListener('fetch', function(event) { hitCounter ; event.respondWith( new Response('Hit number ' hitCounter) ); });

1
2
3
4
5
6
7
8
var hitCounter = 0;
 
this.addEventListener('fetch', function(event) {
  hitCounter ;
  event.respondWith(
    new Response('Hit number ' hitCounter)
  );
});

回到的结果大概是未曾规律的:1,2,1,2,1,1,2….,原因是hitCounter并不曾平素留存,若是浏览器关闭了它,后一次起动的时候hitCounter就赋值为0了
这么的政工导致调节和测验代码困难,当你更新叁个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是否对你的网站启用了。

图片 14

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

您会意识这些效果能够很有益于地在贰个模拟窗口中测验你的service worker,那样您能够关闭和另行张开它,而不会影响到你的新窗口。任何创设在模拟窗口中的注册服务和缓存在窗口被关闭时都将一去不归。

(2)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调节台所示:

图片 15

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要求先生成多个列表。

你只怕会问,当笔者刷新页面包车型客车时候不是又再度挂号安装和激活了多个ServiceWorker?就算又调了一回注册,但并不会重复登记,它发掘”sw-3.js”那么些曾经登记了,就不会再登记了,进而不会触发install和active事件,因为前段时间ServiceWorker已经是active状态了。当须要立异ServiceWorker时,如产生”sw-4.js”,或许改造sw-3.js的文本内容,就能够重新挂号,新的ServiceWorker会先install然后步向waiting状态,等到重启浏览器时,老的ServiceWorker就能够被替换掉,新的ServiceWorker进入active状态,假诺不想等到再也启航浏览器能够像上边同样在install里面调skipWaiting:

JavaScript

this.skipWaiting();

1
this.skipWaiting();

主题材料2. 权力太大

当service worker监听fetch事件之后,对应的呼吁都会透过service worker。通过chrome的network工具,能够看来此类央求会标记:from service worker。固然service worker中出现了难题,会导致全体央浼退步,包含普通的html文件。所以service worker的代码品质、容错性绝对要很好才具确认保证web app符合规律运作。

 

参照小说:

1. 

2. 

3. 

4. 

5. 

1 赞 3 收藏 评论

图片 16

Service Worker的装置步骤

在页面上实现注册手续之后,让咱们把集中力转到service worker的剧本里来,在这里面,大家要到位它的装置步骤。

在最大旨的例子中,你供给为install事件定义三个callback,并操纵怎样文件你想要缓存。

JavaScript

// The files we want to cache var urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; // Set the callback for the install step self.addEventListener('install', function(event) { // Perform install steps });

1
2
3
4
5
6
7
8
9
10
11
// The files we want to cache
var urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];
 
// Set the callback for the install step
self.addEventListener('install', function(event) {
    // Perform install steps
});

在大家的install callback中,我们须要实践以下步骤:

  1. 展开三个缓存
  2. 缓存我们的文本
  3. 支配是还是不是有所的财富是或不是要被缓存

JavaScript

var CACHE_NAME = 'my-site-cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; self.addEventListener('install', function(event) { // Perform install steps event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];
 
self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

地点的代码中,大家透过caches.open展开大家钦定的cache文件名,然后大家调用cache.addAll并传到我们的公文数组。那是通过一种类promise(caches.open 和 cache.addAll)完结的。event.waitUntil得到四个promise并应用它来取得安装花费的大运以及是还是不是安装成功。

假定全数的文书都被缓存成功了,那么service worker就安装成功了。假设别的三个文书下载退步,那么安装步骤就能失败。那一个主意允许你依据于您自个儿钦点的有着财富,可是那表示你需求特别严刻地垄断(monopoly)哪些文件须求在设置步骤中被缓存。钦命了太多的文件的话,就能够扩充设置战败率。

地点只是一个简便的事例,你能够在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。假使央浼战败了,如404大概是过期等等的,那么也一向回到response让主页面管理,不然的话表达加载成功,把那些response克隆一个放置cache里面,然后再回来response给主页面线程。注意能舒缓存里的财富一般只可以是GET,通过POST获取的是不可能缓存的,所以要做个判定(当然你也能够手动把request对象的method改成get),还或然有把有个别私家不愿意缓存的能源也做个决断。

那般只要客户打开过一回页面,ServiceWorker就安装好了,他刷新页面可能展开第一个页面包车型客车时候就能够把须要的能源一一做缓存,富含图片、CSS、JS等,只要缓存里有了不管顾客在线或然离线都能够平日访问。那样我们本来会有一个难题,那个缓存空间到底有多大?上一篇大家提到Manifest也终归地点存款和储蓄,PC端的Chrome是5Mb,其实那么些说法在新本子的Chrome已经不纯粹了,在Chrome 61本子能够见见地方存款和储蓄的空仲春利用状态:

图片 17

当中Cache Storage是指ServiceWorker和Manifest占用的长空尺寸和,上海体育场合能够见到总的空间大小是20GB,大致是unlimited,所以基本上不用忧虑缓存会非常不够用。

怎样缓存和重返Request

您早已设置了service worker,你现在能够重回您缓存的呼吁了。

当service worker被设置成功还要客户浏览了另二个页面大概刷新了当下的页面,service worker将上马收受到fetch事件。上边是四个例子:

JavaScript

self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // Cache hit - return response if (response) { return response; } return fetch(event.request); } ) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }
 
        return fetch(event.request);
      }
    )
  );
});

上边的代码里我们定义了fetch事件,在event.respondWith里,我们传入了一个由caches.match产生的promise.caches.match 查找request中被service worker缓存命中的response。

例如我们有一个命中的response,大家回来被缓存的值,不然大家回去二个实时从网络央求fetch的结果。那是贰个极度轻巧的例证,使用全数在install步骤下被缓存的财富。

借使大家想要增量地缓存新的呼吁,大家得以经过拍卖fetch央求的response何况增进它们到缓存中来达成,举个例子:

JavaScript

self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // Cache hit - return response if (response) { return response; } // IMPORTANT: Clone the request. A request is a stream and // can only be consumed once. Since we are consuming this // once by cache and once by the browser for fetch, we need // to clone the response var fetchRequest = event.request.clone(); return fetch(fetchRequest).then( function(response) { // Check if we received a valid response if(!response || response.status !== 200 || response.type !== 'basic') { return response; } // IMPORTANT: Clone the response. A response is a stream // and because we want the browser to consume the response // as well as the cache consuming the response, we need // to clone it so we have 2 stream. var responseToCache = response.clone(); caches.open(CACHE_NAME) .then(function(cache) { cache.put(event.request, responseToCache); }); return response; } ); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }
 
        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();
 
        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }
 
            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have 2 stream.
            var responseToCache = response.clone();
 
            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });
 
            return response;
          }
        );
      })
    );
});

代码里大家所做事情包含:

  1. 拉长一个callback到fetch央浼的 .then 方法中
  2. 一旦大家赢得了多少个response,大家进行如下的检讨:
    1. 保证response是有效的
    2. 自己商议response的情景是或不是是200
    3. 保障response的项目是basic,那象征乞求笔者是同源的,非同源(即跨域)的呼吁也不能够被缓存。
  3. 即使大家由此了自己争论,clone其一诉求。这么做的因由是一旦response是叁个Stream,那么它的body只可以被读取二次,所以大家得将它克隆出来,一份发给浏览器,一份发给缓存。

(4)cache html

地点第(3)步把图片、js、css缓存起来了,不过一旦把页面html也缓存了,譬喻把首页缓存了,就能够有一个两难的标题——ServiceWorker是在页面注册的,可是以往拿走页面包车型地铁时候是从缓存取的,每便都是一样的,所以就招致力不从心立异ServiceWorker,如形成sw-5.js,可是PWA又须要大家能缓存页面html。那咋办吧?谷歌(Google)的开拓者文书档案它只是提到会存在这么些标题,但并不曾注明怎么解决那一个难题。那个的难题的缓和将必要大家要有三个编写制定能通晓html更新了,进而把缓存里的html给替换掉。

Manifest更新缓存的体制是去看Manifest的文书内容有未有产生变化,假诺产生变化了,则会去立异缓存,ServiceWorker也是依附sw.js的公文内容有未有爆发变化,大家得以借鉴这么些观念,固然央浼的是html并从缓存里抽出来后,再发个伏乞获取一个文书看html更新时间是否产生变化,假设发生变化了则表达产生转移了,进而把缓存给删了。所以可以在服务端通过决定那些文件进而去立异客户端的缓存。如下代码:

JavaScript

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 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的多少依然是和新星update提姆e不一样,则另行去获得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);
    }
});

基于分化的新闻类型调差别的回调函数,假如是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中实行一个管理cache的操作。因为您会供给免去掉在此之前旧的数额。大家在activate并不是install的时候实行那么些操作是因为假诺我们在install的时候立时施行它,那么照旧在运作的旧版本的数据就坏了。

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

上边的代码能够循环全数的缓存,删除掉全数不在白名单中的缓存。

JavaScript

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

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

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

要缓存能够利用三种手段,使用Http Cache设置缓存时间,也能够用Manifest的Application Cache,还能用ServiceWorker缓存,假诺三者都用上了会如何啊?

会以Service Worker为预先,因为ServiceWorker把央浼拦截了,它最早做管理,假诺它缓存库里有的话平素重回,未有的话平常央求,就一定于尚未ServiceWorker了,这年就到了Manifest层,Manifest缓存里假使部分话就取这几个缓存,若无的话就一定于尚未Manifest了,于是就能从Http缓存里取了,假使Http缓存里也从不就能够发哀告去获得,服务端依照Http的etag只怕Modified 提姆e大概会重返304 Not Modified,不然寻常再次来到200和数量内容。这就是整叁个到手的进度。

所以若是既用了Manifest又用ServiceWorker的话应该会招致同五个能源存了四次。可是能够让援救ServiceWorker的浏览器采纳Service Worker,而不援救的接纳Manifest.

拍卖边界和填坑

这一节内容相比新,有相当的多待定细节。希望这一节异常快就没有必要讲了(因为规范会管理这个标题——译者注),可是未来,那些剧情仍旧应当被提一下。

5. 使用Web App Manifest增添桌面入口

留神这里说的是别的多个Manifest,这几个Manifest是二个json文件,用来放网址icon名称等新闻以便在桌面加多三个Logo,以及创造一种张开这几个网页就像张开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缓存:
图片 18把start_url指向的页面用ServiceWorker缓存起来,那样当顾客用Chrome浏览器展开那几个网页的时候,Chrome就能够在尾部弹一个指示,询问顾客是或不是把那几个网页增多到桌面,假如点“增加”就能够调换叁个桌面Logo,从那些Logo点进去就像展开四个App一样。感受如下:

图片 19

正如为难的是Manifest近期独有Chrome帮衬,而且只好在安卓系统上应用,IOS的浏览器不或者增加三个桌面Logo,因为IOS未有开放这种API,可是本身的Safari却又是能够的。

综上,本文介绍了怎么用Service Worker结合Manifest做一个PWA离线Web 应用程式,重借使用ServiceWorker调控缓存,由于是写JS,比较灵敏,还足以与页面进行通讯,其余通过央浼页面包车型大巴立异时间来判别是不是须求创新html缓存。ServiceWorker的包容性不是特地好,不过前景比较光明,浏览器都在备选帮忙。现阶段得以构成offline cache的Manifest做离线应用。

连带阅读:

  1. 为何要把网址升级到HTTPS
  2. 怎么着把网址晋级到http/2
  3. 我是什么样让网址用上HTML5 Manifest

1 赞 1 收藏 评论

图片 20

即使设置失利了,未有很优雅的法子得到通报

假使一个worker被注册了,可是未有现身在chrome://inspect/#service-workers或chrome://serviceworker-internals,那么很可能因为异常而安装失败了,或者是产生了一个被拒绝的的promise给event.waitUtil。

要缓和这类难点,首先到 chrome://serviceworker-internals检查。打开开发者工具窗口准备调试,然后在你的install event代码中添加debugger;语句。这样,通过断点调试你更容易找到问题。

fetch()近些日子仅支持Service Workers

fetch立时协理在页面上应用了,然而当前的Chrome完毕,它还只辅助service worker。cache API也就要要页面上被协理,然则如今甘休,cache也还不得不在service worker中用。

fetch()的暗许参数

当你利用fetch,缺省级地区级,央浼不会带上cookies等凭证,要想带上的话,需求:

JavaScript

fetch(url, { credentials: 'include' })

1
2
3
fetch(url, {
  credentials: 'include'
})

如此那般设计是有理由的,它比XHRAV4的在同源下默许发送凭据,但跨域时扬弃凭据的条条框框要来得好。fetch的行为更像其余的CO奇骏S诉求,比如<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

Non-CORAV4S私下认可不援救

默许情状下,从第三方USportageL跨域得到贰个能源将会倒闭,除非对方协助了COLANDS。你可以加上二个non-COPAJEROS选项到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.');
});

fetch()不服从30x重定向标准

不幸,重定向在fetch()中不会被触发,这是眼前版本的bug;

管理响应式图片

img的srcset属性恐怕<picture>标签会根据情况从浏览器或者网络上选择最合适尺寸的图片。

在service worker中,你想要在install步骤缓存贰个图片,你有以下三种选拔:

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

相比较好的方案是2或3,因为一旦把具备的图纸都给下载下来存着有一些浪费内部存款和储蓄器。

假诺你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互连网上下载high-res的版本,可是倘诺high-res版本下载失利以来,就照样用low-res版本。那么些主见很好也值得去做,不过有二个题目:

一经咱们有上面二种图片:

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

HTML代码如下:

JavaScript

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

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

假如大家在一个2x的体现方式下,浏览器会下载image-2x.png,即使大家离线,你能够读取此前缓存并赶回image-src.png代替,假设此前它早就被缓存过。纵然如此,由于未来的方式是2x,浏览器会把400X400的图形显示成200X200,要幸免这么些难点即就要图纸的体制上安装宽高。

JavaScript

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

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

图片 21

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

改变URL Hash的Bug

在M40版本中留存多个bug,它会让页面在转移hash的时候形成service worker结束专门的职业。

你能够在此处找到更加多相关的信息: 

越多内容

此处有一点互为表里的文档能够参照:

赢得赞助

例如您越过麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家当即跟进和不择手腕帮忙你消除难点。

赞 2 收藏 评论

图片 22

本文由星彩网app下载发布于前端技术,转载请注明出处:英帝国卫报的天性离线页面是这么做的,离线网

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。