澳门新萄京离线访问静态blog网站,离线网页应用
分类:澳门新萄京最大平台

运用 Service worker 创立一个特别轻便的离线页面

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

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

让我们想像以下场景:大家那时候在一辆通往农村的高铁上,用运动道具看着一篇很棒的小说。与此同有时候,当你点击“查看越多”的链接时,高铁蓦地走入了隧道,导致运动设备失去了互联网,而 web 页面会展现出类似以下的剧情:

澳门新萄京 1

这是分外令人颓丧的经验!幸运的是,web 开荒者们能透过有个别新天性来立异那类的客商体验。作者如今间接在折腾 ServiceWorkers,它给 web 带来的成千上万恐怕性总能给自个儿喜悦。Service Workers 的精良特质之一是同意你检查评定互联网央求的景观,并令你作出相应的响应。

在那篇小说里,笔者图谋用此特性检查客户的当前互联网连接景况,假设没连接则赶回二个最棒轻松的离线页面。就算那是二个老大基础的案例,但它能给您带来启迪,让您了解运营并运转该个性是多么的简短!假诺您没掌握过 Service Worker,作者提出您看看此 Github repo,理解越多相关的新闻。

在此案例初叶前,让大家先简单地寻访它的办事流程:

  1. 在客商第叁回访问大家的页面时,大家会设置 ServiceWorker,并向浏览器的缓存增添大家的离线 HTML 页面
  2. 下一场,假设顾客图谋导航到另三个 web 页面(同多少个网址下),但此时已断网,那么大家将赶回已被缓存的离线 HTML 页面
  3. 不过,如若客户企图导航到其他三个 web 页面,而此刻网络已再而三,则能照常浏览页面

利用Service worker完结加速/离线访谈静态blog网址

2017/02/19 · JavaScript · Service Worker

初稿出处: Yang Bo   

近来非常的火基于Github page和markdown的静态blog,特别相符手艺的思辨和习贯,针对分歧的语言都有一对地利人和的静态blog系统出现,如Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于静态内容的天性特别相符做缓存来增长速度页面包车型地铁拜望,就采纳Service worker来完结加速,结果是除了PageSpeed,CDN这么些科学普及的服务器和互联网加速之外,通过客商端完结了越来越好的会见体验。

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

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

本文由 伯乐在线 - Erucy 翻译,weavewillg 校稿。未经许可,制止转载!
斯洛伐克语出处:Oliver Ash。应接参加翻译组。

大家是如何运用 service worker 来为 theguardian.com 创设三个自定义的离线页面。

澳门新萄京 2

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

你正在朝着公司途中的大巴里,在表弟大上开拓了 Guardian 应用。大巴被隧道包围着,可是那一个动用能够健康运行,即使未有网络连接,你也能博取完整的法力,除了出示的剧情大概有一些旧。即便你尝试在网址上也如此干,缺憾它完全没办法加载:

澳门新萄京 3

安卓版 Chrome 的离线页面

Chrome 中的这么些彩蛋,很四人都不清楚》

Chrome 在离线页面上有个藏匿的玩乐(桌面版上按空格键,手提式有线电话机版上点击那只恐龙),那多少能减轻一点您的愤懑。可是大家可以做得更加好。

Service workers 允许网址小编拦截自身站点的富有网络央浼,那也就代表大家能够提供全面的离线体验,如同原生应用一样。在 Guardian 网站,大家多年来上线了贰个自定义的离线体验效果。当客户离线的时候,他们拜望到三个包括Guardian 标识的页面,上边带有二个简短的离线提醒,还应该有多个填字游戏,他们得以在等待网络连接的时候玩玩那些找点乐子。那篇博客解释了我们是哪些营造它的,不过在初叶以前,你能够先本人试试看。

Service Worker入门

2015/03/26 · JavaScript · Service Worker

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

  • 十年踪迹]()   

原生App具有Web应用日常所不具有的富离线体验,定期的沉默更新,新闻公告推送等职能。而新的Serviceworkers标准让在Web App上具备那些效应成为大概。

采纳 瑟维斯 Worker 做三个 PWA 离线网页应用

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

初稿出处: 人人网FED博客   

在上一篇《自个儿是何许让网址用上HTML5 Manifest》介绍了怎么用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 时,向缓存增添了离线页面。如若大家将代码分为几小块,可知到前几行代码中,作者为离线页面钦定了缓存版本和UPAJEROL。假诺您的缓存有两样版本,那么你只需立异版本号就可以轻便地清除缓存。在大意在第 12 行代码,作者向这几个离线页面及其能源(如:图片)发出乞求。在收获成功的响应后,大家将离线页面和连锁能源丰盛到缓存。

于今,离线页面已存进缓存了,大家可在急需的时候检索它。在同三个 ServiceWorker 中,我们供给对无互联网时再次来到的离线页面加多相应的逻辑代码。

JavaScript

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

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

为了测验该意义,你能够行使 Chrome 内置的开荒者工具。首先,导航到你的页面,然后一旦设置上了 ServiceWorker,就展开 Network 标签并将节流(throttling)改为 Offline。(译者注:若将节流设置为 Offline 没意义,则可经过关闭网络只怕通过360安然无恙警卫禁绝 Chrome 访谈互连网)

澳门新萄京 4

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

澳门新萄京 5

万一您只想大致地测验该成效而不想写任何代码,那么您可以访谈作者已开立好的 demo。别的,上述总体代码能够在 Github repo 找到。

本人清楚用在此案例中的页面很简单,但您的离线页面则在于你协调!借使您想长远该案例的源委,你可以为离线页面加多缓存破坏( cache busting),如: 此案例。

加速/离线访问只需三步

  • 首页增多注册代码

JavaScript

<script> if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); } </script>

1
2
3
4
5
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
</script>
  • 复制代码

将保存到您的网址根目录下

  • 修改不缓存域名列表及离线状态页面

在你的sw.js中修改

JavaScript

const ignoreFetch = [ /https?://cdn.bootcss.com//, /https?://static.duoshuo.com//, /https?://www.google-analytics.com//, /https?://dn-lbstatics.qbox.me//, ];

1
2
3
4
5
6
const ignoreFetch = [
  /https?://cdn.bootcss.com//,
  /https?://static.duoshuo.com//,
  /https?://www.google-analytics.com//,
  /https?://dn-lbstatics.qbox.me//,
];

打开Chrome Dev Tools->Source,看看本人的blog都援引了如何第三方能源,每个加到忽略列表里。

澳门新萄京 6

在根目录下加多offline.html,在并未有互联网且缓存中也未曾时选用,效果如下:

澳门新萄京 7

在根目录下增加offline.svg,在无互联网时图片能源诉求再次回到该文件。

试试看

你需求七个帮助 Service Worker 和 fetch API 的浏览器。截至到本文编写时独有Chrome(手提式有线电话机版和桌面版)同一时间帮忙那二种 API(译者注:Opera 前段时间也帮衬这两个),但是 Firefox 相当慢就要帮助了(在每一天更新的版本中早已支撑了),除开 Safari 之外的有所浏览器也都在尝试。其余,service worker 只可以登记在选取了 HTTPS 的网址上,theguardian.com 已经上马逐年搬迁到 HTTPS,所以大家只能在网址的 HTTPS 部分提供离线体验。就当前以来,大家选用了 开辟者博客 作为大家用来测验的地点。所以只要您是在我们网址的 开拓者博客 部分阅读那篇小说的话,很幸运。

当您使用协助的浏览器访谈大家的 开辟者博客 中的页面包车型大巴时候,一切就希图妥帖了。断开你的网络连接,然后刷新一下页面。要是您自己没条件尝试的话,能够看一下这段 演示摄像(译者注:需梯子)。

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的具体表现是何许的啊?如下图所示:

澳门新萄京 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降为1,加载时间从2.296s降为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(它是 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初次安装的生命周期:

澳门新萄京 11

2. Service Worker的帮助景况

瑟维斯 Worker近来独有Chrome/Firfox/Opera扶助:

澳门新萄京 12

Safari和Edge也在预备扶助Service Worker,由于ServiceWorker是Google着力的一项专门的学业,对于生态比较密封的Safari来讲也是迫于时势开端盘算援救了,在Safari TP版本,能够见到:

澳门新萄京 13

在实验功用(Experimental Features)里曾经有ServiceWorker的菜单项了,只是就算打开也是不可能用,会提示您还一直不兑现:

澳门新萄京 14

但无论是怎样,最少表明Safari已经希图帮忙瑟维斯Worker了。别的还是能够见见在当年二〇一七年6月发表的Safari 11.0.1本子已经协理WebRTC了,所以Safari照旧三个迈入的男女。

Edge也策动帮衬,所以Service Worker的前景十三分美好。

打赏支持本身翻译更加的多好小说,感激!

任选一种支付格局

澳门新萄京 15 澳门新萄京 16

1 赞 3 收藏 1 评论

加紧/离线原理探究

打赏扶助笔者翻译越多好小说,多谢!

澳门新萄京 17

1 赞 收藏 评论

在大家初始写码在此以前

从这个品种地址拿到chaches polyfill。

这个polyfill支持CacheStorate.match,Cache.add和Cache.addAll,而现在Chrome M40实现的Cache API还从未帮忙那些办法。

将dist/serviceworker-cache-polyfill.js放到你的网址中,在service worker中经过importScripts加载进来。被service worker加载的剧本文件会被自动缓存。

JavaScript

importScripts('serviceworker-cache-polyfill.js');

1
importScripts('serviceworker-cache-polyfill.js');

需要HTTPS

在开荒阶段,你能够通过localhost使用service worker,不过一旦上线,就供给您的server支持HTTPS。

您能够由此service worker威胁连接,伪造和过滤响应,非常逆天。尽管你能够约束自身不干坏事,也是有人想干坏事。所认为了防止外人使坏,你只可以在HTTPS的网页上注册service workers,那样我们才具够免止加载service worker的时候不被渣男篡改。(因为service worker权限异常的大,所以要防御它自个儿被混蛋篡改利用——译者注)

Github Pages碰巧是HTTPS的,所以它是八个妙不可言的天赋实验田。

万一你想要令你的server协助HTTPS,你需求为您的server获得叁个TLS证书。分歧的server安装方法分歧,阅读扶助文书档案并经过Mozilla’s SSL config generator问询最好试行。

3. 使用Service Worker

ServiceWorker的运用套路是先挂号四个Worker,然后后台就能运维一条线程,能够在那条线程运行的时候去加载一些能源缓存起来,然后监听fetch事件,在这几个事件里拦截页面的伸手,先看下缓存里有未有,借使有直接重返,不然符合规律加载。恐怕是一开端不缓存,每种财富央求后再拷贝一份缓存起来,然后下三次呼吁的时候缓存里就有了。

有关作者:刘健超-J.c

澳门新萄京 18

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

澳门新萄京 19

什么是 Service worker

澳门新萄京 20

如上图,Service worker 是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当七个页面注册了一个 Service worker,它就足以登记一层层事件管理器来响应如互连网央求和新闻推送那一个事件。Service worker 能够被用来治本缓存,当响应多个网络央求时方可安插为回到缓存依然从网络获取。由于Service worker 是依赖事件的,所以它只在管理那个事件的时候被调入内部存款和储蓄器,不用忧郁常驻内部存储器占用能源导致系统变慢。

至于小编:Erucy

澳门新萄京 21

早已的SharePoint喵星程序员(权且还挂着微软MVP的名头),未来的Azure/.Net/MongoDB/Cordova/前端技术员,有时写小说 个人主页 · 笔者的篇章 · 46 ·   

澳门新萄京 22

使用Service Worker

近些日子我们有了polyfill,並且消除了HTTPS,让咱们看看见底怎么用service worker。

(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和带宽的,大家应该保证页面能健康加载完,然后再开发银行大家的后台线程,不可能与健康的页面加载发生竞争,那几个在低等移动设备意义一点都不小。

再有少数亟待注意的是ServiceWorker和Cookie同样是有帕特h路线的概念的,如若您设定一个cookie要是叫time的path=/page/A,在/page/B这几个页面是不能获得到那个cookie的,假如设置cookie的path为根目录/,则有所页面都能赢获得。类似地,要是注册的时候利用的js路线为/page/sw.js,那么那个ServiceWorker只可以处理/page路线下的页面和财富,而不可见管理/api路线下的,所以日常把ServiceWorker注册到拔尖目录,如上边代码的”/sw-3.js”,那样这些ServiceWorker就会接管页面包车型大巴全体能源了。

Service worker生命周期

澳门新萄京 23

Service worker 为网页增多一个临近于APP的生命周期,它只会响应系统事件,固然浏览器关闭时操作系统也得以唤起Service worker,那一点非常重要,让web app与native app的本领变得好像了。

Service worker在Register时会触发Install事件,在Install时能够用来预先获取和缓存应用所需的能源并设置每一个文件的缓存计谋。

一旦Service worker高居activated状态,就足以完全调整应用的财富,对互连网央浼进行自己商量,修改网络央浼,从互连网上获得并回到内容或许重回由已安装的Service worker预示获取并缓存好的财富,以致还足以变动内容并赶回给网络语法。

具备的这个都客商都以晶莹的,事实上,一个统一妄想美貌的Service worker就像三个智能缓存系统,狠抓了网络和缓存功用,选用最优办法来响应互联网央浼,让动用更加的安宁的运行,纵然未有互连网也没涉及,因为您能够完全调整网络响应。

怎么着注册和装置service worker

要设置service worker,你须求在你的页面上登记它。那些手续告诉浏览器你的service worker脚本在何地。

JavaScript

if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }

1
2
3
4
5
6
7
8
9
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    // Registration was successful
    console.log('ServiceWorker registration successful with scope: ',    registration.scope);
  }).catch(function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
}

地方的代码检查service worker API是或不是可用,倘诺可用,service worker /sw.js 被注册。

假定这几个service worker已经被注册过,浏览器会活动忽略上面的代码。

有多个亟需特意表明的是service worker文件的路径,你断定注意到了在那个事例中,service worker文件被放在这几个域的根目录下,那象征service worker和网址同源。换句话说,这些service work将会接收这些域下的保有fetch事件。假诺自己将service worker文件注册为/example/sw.js,那么,service worker只能收到/example/路径下的fetch事件(例如: /example/page1/, /example/page2/)。

近期你能够到 chrome://inspect/#service-workers 检查service worker是否对你的网站启用了。

澳门新萄京 24

当service worker第一版被完成的时候,你也得以在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.addEventListener("install", function(event) { this.skipWaiting(); console.log("install service worker"); // 创立和开发三个缓存库 caches.open(CACHE_NAME); // 首页 let cacheResources = ["]; event.waitUntil( // 伏乞财富并增加到缓存里面去 caches.open(CACHE_NAME).then(cache => { cache.addAll(cacheResources); }) ); });

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

由此地方的操作,创造和增加了贰个缓存库叫fed-cache,如下Chrome调整台所示:

澳门新萄京 25

ServiceWorker的API基本上都以回来Promise对象制止堵塞,所以要用Promise的写法。上边在设置ServiceWorker的时候就把首页的央浼给缓存起来了。在ServiceWorker的运维情状之中它有四个caches的大局对象,那几个是缓存的入口,还应该有一个常用的clients的大局对象,三个client对应一个标签页。

在ServiceWorker里面能够利用fetch等API,它和DOM是与世隔膜的,未有windows/document对象,无法间接操作DOM,不可能直接和页面交互,在ServiceWorker里面不能获知当前页面张开了、当前页面包车型地铁url是什么样,因为两个ServiceWorker管理当前展开的多少个标签页,能够由此clients知道全部页面的url。还会有能够通过postMessage的法子和主页面相互传送新闻和多少,进而做些调节。

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

JavaScript

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

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

ServiceWorker激活之后就可以监听fetch事件了,大家期望每获得三个能源就把它缓存起来,就不要像上一篇涉嫌的Manifest须求先生成三个列表。

您大概会问,当自家刷新页面包车型客车时候不是又重新挂号安装和激活了八个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();

Service worker的支配从第壹遍页面访谈开头

在第三遍加载页面时,全体财富都是从互连网载的,Service worker 在第一回加载时不会获取调整互联网响应,它只会在继续访谈页面时起作用。

澳门新萄京 26

页面第一遍加载时做到install,并步入idle状态。

澳门新萄京 27

页面第三遍加载时,踏入activated状态,绸缪管理不论什么事件,同时 浏览器会向服务器发送贰个异步 乞请来检查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. 翻开一个缓存
  2. 缓存大家的公文
  3. 决定是或不是享有的能源是或不是要被缓存

JavaScript

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

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

上边的代码中,我们由此caches.open展开我们钦点的cache文件名,然后我们调用cache.addAll并传播我们的文书数组。那是经过种类promise(caches.open 和 cache.addAll)完成的。event.waitUntil获得二个promise并利用它来获取安装成本的时间以及是还是不是安装成功。

只要具备的文本都被缓存成功了,那么service worker就设置成功了。如若别的多少个文书下载战败,那么安装步骤就能够停业。那么些措施允许你依赖于您和煦钦赐的具有财富,可是这象征你须求格外谦虚审慎地调控如何文件要求在设置步骤中被缓存。钦点了太多的文书的话,就能追加设置失利率。

上边只是三个轻松的例证,你能够在install事件中推行另外操作依然以致忽视install事件。

(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都一律才是一律的财富,能够设定第4个参数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就安装好了,他刷新页面大概张开第4个页面包车型大巴时候就能够把乞求的财富一一做缓存,包含图片、CSS、JS等,只要缓存里有了不管顾客在线或然离线都能够健康访谈。那样我们自然会有二个难题,这么些缓存空间到底有多大?上一篇我们提到Manifest也总算地点存款和储蓄,PC端的Chrome是5Mb,其实那么些说法在新本子的Chrome已经不精确了,在Chrome 61版本能够看见本地存款和储蓄的上空和采纳境况:

澳门新萄京 29

其间Cache Storage是指ServiceWorker和Manifest占用的空中山大学小和,上海教室能够看见总的空间尺寸是20GB,差不离是unlimited,所以基本上不用忧郁缓存会非常不够用。

特点

  • 浏览器

Google Chrome,Firefox,Opera以及本国的各个双核浏览器都帮助,但是 safari 不协理,那么在不扶助的浏览器里Service worker不工作。

  • https

网址必需启用https来担保使用Service worker页面包车型客车安全性,开垦时localhost暗许认为是安全的。

  • non-block

Service worker 中的 Javascript 代码必需是非阻塞的,因为 localStorage 是阻塞性,所以不该在 瑟维斯 Worker 代码中采纳 localStorage。

  • 单独的实践境遇

Service worker运行在和煦的全局景况中,日常也运营在协调单独的线程中。

  • 未曾绑定到特定页面

service work能操纵它所加载的成套范围内的能源。

  • 不可能操作DOM

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

澳门新萄京 30

  • 从没浏览页面时也能够运维

收到系统事件,后台运维

  • 事件驱动,须求时运转,无需时就告一段落

按需推行,只在要求时加载到内部存款和储蓄器

  • 可升级

实行时会异步获取最新的本子

哪些缓存和重返Request

您曾经设置了service worker,你未来能够回去您缓存的央求了。

当service worker被设置成功还要客商浏览了另叁个页面可能刷新了当下的页面,service worker将起来抽取到fetch事件。上面是八个例子:

JavaScript

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

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

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

若果大家有四个命中的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也缓存了,举个例子把首页缓存了,就能够有三个两难的主题素材——瑟维斯Worker是在页面注册的,然这段时间后拿走页面包车型地铁时候是从缓存取的,每一次都以一模二样的,所以就形成敬敏不谢立异瑟维斯Worker,如形成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 UEnclaveL(event.request.url); util.updateHtmlPage(url, event.request.clone(), event.clientId); } return response; } return util.fetchPut(event.request.clone()); }) ); });

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

因此响应头header的content-type是或不是为text/html,若是是的话就去发个乞请获取叁个文件,依据这么些文件的剧情决定是还是不是要求删除缓存,那几个立异的函数util.updateHtmlPage是那般实现的:

JavaScript

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

  • url); cache.delete(url, {ignoreVary: true}); }); } };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let pageUpdateTime = {
 
};
let util = {
    updateHtmlPage: function (url, htmlRequest) {
        let pageName = util.getPageName(url);
        let jsonRequest = new Request("/html/service-worker/cache-json/" pageName ".sw.json");
        fetch(jsonRequest).then(response => {
            response.json().then(content => {
                if (pageUpdateTime[pageName] !== content.updateTime) {
                    console.log("update page html");
                    // 如果有更新则重新获取html
                    util.fetchPut(htmlRequest);
                    pageUpdateTime[pageName] = content.updateTime;
                }
            });
        });
    },
    delCache: function (url) {
        caches.open(CACHE_NAME).then(cache => {
            console.log("delete cache " url);
            cache.delete(url, {ignoreVary: true});
        });
    }
};

澳门新萄京,代码先去猎取一个json文件,二个页面会对应二个json文件,这些json的剧情是如此的:

JavaScript

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

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

其中首要有三个updateTime的字段,如若本地内部存款和储蓄器未有那几个页面包车型地铁updateTime的数目依然是和新颖updateTime不平等,则重复去赢得 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把伏乞拦截了,它首先做拍卖,假如它缓存Curry一些话一贯回到,未有的话不奇怪供给,就也正是尚未ServiceWorker了,这年就到了Manifest层,Manifest缓存里若是有的话就取这么些缓存,如果没有的话就一定于尚未Manifest了,于是就能从Http缓存里取了,假若Http缓存里也未尝就能够发诉求去获得,服务端遵照Http的etag只怕Modified Time或者会回去304 Not Modified,不然正常重回200和数据内容。那正是整三个获得的进度。

据此一旦既用了Manifest又用ServiceWorker的话应该会变成同贰个财富存了一回。可是可以让辅助ServiceWorker的浏览器接纳Service Worker,而不辅助的应用Manifest.

Cache

网页缓存有数不胜数,如HTTP缓存,localStorage,sessionStorage和cacheStorage都能够灵活搭配实行缓存,但操作太繁琐,直接利用更加高等Service worker –本文的庄家。

拍卖边界和填坑

这一节内容相比较新,有众多待定细节。希望这一节异常快就无需讲了(因为标准会管理那些主题材料——译者注),不过现在,那几个剧情还是应该被提一下。

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缓存:
澳门新萄京 31把start_url指向的页面用ServiceWorker缓存起来,那样当顾客用Chrome浏览器展开那么些网页的时候,Chrome就能够在尾巴部分弹三个提醒,询问客户是还是不是把这几个网页加多到桌面,假若点“加多”就能够扭转二个桌面图标,从这几个Logo点进去就像是展开叁个App一样。感受如下:

澳门新萄京 32

正如为难的是Manifest方今独有Chrome援救,况且只可以在安卓系统上选择,IOS的浏览器不能够增添三个桌面Logo,因为IOS未有开放这种API,然则本身的Safari却又是能够的。

综上,本文介绍了怎么用Service Worker结合Manifest做一个PWA离线Web APP,首若是用ServiceWorker调控缓存,由于是写JS,相比较灵敏,还足以与页面实行通讯,别的通过伏乞页面包车型客车更新时间来判别是不是须要革新html缓存。ServiceWorker的包容性不是特意好,可是前景相比较光明,浏览器都在预备补助。现阶段得以结合offline cache的Manifest做离线应用。

相关阅读:

  1. 干什么要把网址进级到HTTPS
  2. 怎么样把网址进级到http/2
  3. 自己是怎么样让网址用上HTML5 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能够垄断(monopoly)网址有着的页面,,同理,假设把sw.js放在/my-app/sw.js那便是说它只可以调整my-app目录下的页面。
sw.js放在/js/目录呢?更加好的目录结商谈范围调控呢?
在注册时钦点js位置并设置限制。

JavaScript

navigator.serviceWorker.register('/js/sw.js', {scope: '/sw-test/'}).then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); });

1
2
3
4
5
6
7
navigator.serviceWorker.register('/js/sw.js', {scope: '/sw-test/'}).then(function(registration) {
      // Registration was successful
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }).catch(function(err) {
      // registration failed :(
      console.log('ServiceWorker registration failed: ', err);
    });

如果设置退步了,未有异常高雅的不二秘籍获得通报

设若二个worker被登记了,不过未有出现在chrome://inspect/#service-workers或chrome://serviceworker-internals,那么很可能因为异常而安装失败了,或者是产生了一个被拒绝的的promise给event.waitUtil。

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

Service worker实现

监听七个事件:

JavaScript

self.addEventListener('install', onInstall); self.addEventListener('fetch', onFetch); self.addEventListener("activate", onActivate);

1
2
3
self.addEventListener('install', onInstall);
self.addEventListener('fetch', onFetch);
self.addEventListener("activate", onActivate);

fetch()近期仅援救Service Workers

fetch立刻扶助在页面上使用了,可是当前的Chrome完结,它还只扶助service worker。cache API也将在要页面上被扶助,不过近年来甘休,cache也还不得不在service worker中用。

install

JavaScript

////////// // Install ////////// function onInstall(event) { log('install event in progress.'); event.waitUntil(updateStaticCache()); } function updateStaticCache() { return caches .open(cacheKey('offline')) .then((cache) => { return cache.addAll(offlineResources); }) .then(() => { log('installation complete!'); }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//////////
// Install
//////////
function onInstall(event) {
  log('install event in progress.');
  event.waitUntil(updateStaticCache());
}
function updateStaticCache() {
  return caches
    .open(cacheKey('offline'))
    .then((cache) => {
      return cache.addAll(offlineResources);
    })
    .then(() => {
      log('installation complete!');
    });
}

install时将持有切合缓存计谋的能源进行缓存。

fetch()的暗许参数

当你选取fetch,缺省级地区级,诉求不会带上cookies等凭证,要想带上的话,供给:

JavaScript

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

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

这么设计是有理由的,它比XH福睿斯的在同源下暗中认可发送凭据,但跨域时屏弃凭据的平整要来得好。fetch的一言一动更像另外的COCRUISERS央浼,比方<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-COCRUISERS暗中认可不协理

默许情形下,从第三方U奥迪Q5L跨域获得一个财富将会战败,除非对方支持了CO昂科雷S。你能够拉长三个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步骤缓存八个图形,你有以下二种选拔:

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

澳门新萄京 34

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

一定网址

  1. Google Chrome

Developer Tools->Application->Service Workers

澳门新萄京 35

在那边还会有多少个特别实用的复选框:

  • Offline

澳门新萄京离线访问静态blog网站,离线网页应用。宪章断网状态

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

除非在Settings里有二个得以在HTTP情况中动用Service worker的选项,适应于调节和测量检验,未有单独网址下的Service worker管理。

澳门新萄京 36

  1. Opera及任何双核浏览器同Google Chrome
    假设看见多少个一律范围内的多少个Service worker,说明Service woker更新后,而原有Service worker还一直不被terminated。

改变URL Hash的Bug

在M40版本中留存多少个bug,它会让页面在转移hash的时候变成service worker停止职业。

你能够在那边找到更加的多相关的音信: 

浏览器全局

探望您的浏览器里都有如何Service worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

能够看见已经有25个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及另外双核浏览器同谷歌 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

本文由澳门新萄京发布于澳门新萄京最大平台,转载请注明出处:澳门新萄京离线访问静态blog网站,离线网页应用

上一篇:没有了 下一篇:没有了
猜你喜欢
热门排行
精彩图文