澳门新萄京连不上网,创建一个非常简单的离线
分类:澳门新萄京最大平台

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

2017/02/19 · JavaScript · Service Worker

初稿出处: Yang Bo   

现行反革命很盛行基于Github page和markdown的静态blog,非常符合本事的记挂和习贯,针对差异的言语都有部分神奇的静态blog系统出现,如Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于静态内容的特征特别相符做缓存来增长速度页面包车型客车探望,就使用Service worker来贯彻加速,结果是除了PageSpeed,CDN那么些大面积的服务器和网络加速之外,通过客户端达成了越来越好的访谈体验。

Service Worker入门

2015/03/26 · JavaScript · Service Worker

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

  • 十年踪迹]()   

原生App具备Web应用普通所不有所的富离线体验,定期的默不做声更新,新闻文告推送等作用。而新的Serviceworkers规范让在Web App上保有那个功用成为大概。

运用 Service worker 成立二个特别轻松的离线页面

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

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

让大家想像以下境况:大家那儿在一辆通往农村的列车里,用移动设备看着一篇很棒的小说。与此相同的时候,当您点击“查看越多”的链接时,高铁顿然步向了隧道,导致移动装备失去了互联网,而 web 页面会显示出类似以下的剧情:

澳门新萄京 1

那是非常令人寒心的感受!幸运的是,web 开垦者们能通过一些新特点来革新这类的顾客体验。作者近些日子直接在折腾 ServiceWorkers,它给 web 带来的成千上万恐怕性总能给本人惊奇。瑟维斯 Workers 的可观特质之一是允许你检验网络央浼的景色,并让您作出相应的响应。

在那篇小说里,作者准备用此性格检查客户的脚下互联网连接处境,要是没连接则赶回二个至上简单的离线页面。固然那是贰个特出基础的案例,但它能给您带来启迪,令你通晓运转并运维该天性是多么的简约!假使您没掌握过 Service Worker,作者提议你看看此 Github repo,精晓越来越多相关的音信。

在该案例开首前,让我们先轻便地看看它的工作流程:

  1. 在用户第三次访问大家的页面时,大家会设置 ServiceWorker,并向浏览器的缓存增加我们的离线 HTML 页面
  2. 然后,即使顾客希图导航到另三个 web 页面(同三个网址下),但此时已断网,那么我们将重临已被缓存的离线 HTML 页面
  3. 不过,假诺客户图谋导航到其余八个 web 页面,而那时候互联网已接连,则能照常浏览页面

连不上网?大不列颠及英格兰联合王国卫报的脾性离线页面是这么做的

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 做一个 PWA 离线网页应用

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

初稿出处: 人人网FED博客   

在上一篇《小编是怎么让网址用上HTML5 Manifest》介绍了怎么用Manifest做多个离线网页应用,结果被大面积网上朋友戏弄说那些东西已经被deprecated,移出web标准了,将来被ServiceWorker取代了,不管怎么,Manifest的一对谋算依旧得以借用的。小编又将网址晋级到了ServiceWorker,要是是用Chrome等浏览器就用ServiceWorker做离线缓存,固然是Safari浏览器就依然用Manifest,读者能够展开这些网址感受一下,断网也是能日常展开。

加快/离线访谈只需三步

  • 首页增加注册代码

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都援引了何等级三方能源,各种加到忽略列表里。

澳门新萄京 4

在根目录下增加offline.html,在尚未互连网且缓存中也向来临时行使,效果如下:

澳门新萄京 5

在根目录下增添offline.svg,在无互连网时图片财富须要重临该公文。

Service Worker 是什么?

四个 service worker 是一段运转在浏览器后台进度里的本子,它独自于近期页面,提供了那么些无需与web页面交互的意义在网页背后悄悄推行的技能。在以后,基于它能够兑现消息推送,静默更新以及地理围栏等劳动,不过这两天它首先要具有的功效是阻挡和管理互连网央浼,包涵可编制程序的响应缓存管理。

为何说这一个API是一个老大棒的API呢?因为它使得开拓者能够帮助非常好的离线体验,它赋予开荒者完全调节离线数据的技巧。

在service worker提议以前,别的七个提供开荒者离线体验的API叫做App Cache。但是App Cache有些局限性,譬喻它能够很轻便地消除单页应用的题材,可是在多页应用上会很辛劳,而Serviceworkers的面世正是为了减轻App Cache的痛点。

上边详细说一下service worker有何需求注意的地点:

  • 它是JavaScript Worker,所以它无法一贯操作DOM。不过service worker可以通过postMessage与页面之间通讯,把音讯通告给页面,假若须求的话,让页面本人去操作DOM。
  • Serviceworker是四个可编制程序的网络代理,允许开荒者调整页面上处理的互联网伏乞。
  • 在不被运用的时候,它会和睦终止,而当它再也被用到的时候,会被再一次激活,所以你不能够借助于service worker的onfecth和onmessage的管理函数中的全局状态。假若您想要保存一些漫长化的消息,你能够在service worker里使用IndexedDB API。
  • Serviceworker多量使用promise,所以假若您不掌握什么是promise,那您必要先读书这篇文章。

让我们起头吧

一经你有以下 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 时,向缓存增添了离线页面。假如大家将代码分为几小块,可知到前几行代码中,笔者为离线页面钦定了缓存版本和U路虎极光L。假使您的缓存有两样版本,那么你只需立异版本号就能够轻易地清除缓存。在大概在第 12 行代码,笔者向那一个离线页面及其能源(如:图片)发出央浼。在收获成功的响应后,大家将离线页面和相关财富足够到缓存。

今后,离线页面已存进缓存了,大家可在要求的时等候检查索它。在同贰个 ServiceWorker 中,大家必要对无网络时回来的离线页面加多相应的逻辑代码。

JavaScript

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

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

为了测量检验该功能,你可以使用 Chrome 内置的开拓者工具。首先,导航到您的页面,然后借使设置上了 ServiceWorker,就开拓 Network 标签并将节流(throttling)改为 Offline。(译者注:若将节流设置为 Offline 没效果,则可通过关闭网络可能经过360有惊无险警卫制止 Chrome 访问互连网)

澳门新萄京 6

若果你刷新页面,你应该能来看相应的离线页面!

澳门新萄京 7

若是您只想大致地质度量试该意义而不想写任何代码,那么你能够访谈作者已开立好的 demo。别的,上述全体代码可以在 Github repo 找到。

本人驾驭用在此案例中的页面很简短,但您的离线页面则决计于你自身!倘让你想深切该案例的内容,你可以为离线页面增添缓存破坏( cache busting),如: 此案例。

试试看

你供给贰个支撑 Service Worker 和 fetch API 的浏览器。停止到本文编写时唯有Chrome(手机版和桌面版)同时帮助那三种 API(译者注:Opera 近来也支撑这两个),不过 Firefox 异常快将在协助了(在每一天更新的本子中早就支撑了),而外 Safari 之外的享有浏览器也都在查究。其它,service worker 只可以登记在使用了 HTTPS 的网址上,theguardian.com 已经上马稳步搬迁到 HTTPS,所以我们只还好网址的 HTTPS 部分提供离线体验。就当前来说,大家选择了 开发者博客 作为我们用来测量检验的地点。所以只要你是在大家网址的 开垦者博客 部分阅读那篇小说的话,很幸运。

当你使用协理的浏览器访谈大家的 开垦者博客 中的页面包车型大巴时候,一切就筹算伏贴了。断开你的网络连接,然后刷新一下页面。假令你协调没标准尝试的话,能够看一下这段 躬体力行录像(译者注:需梯子)。

1. 什么是Service Worker

Service Worker是谷歌倡导的兑现PWA(Progressive Web App)的贰个根本剧中人物,PWA是为着消除古板Web APP的劣点:

(1)未有桌面入口

(2)无法离线使用

(3)没有Push推送

澳门新萄京,那瑟维斯 Worker的具体表现是哪些的吧?如下图所示:

澳门新萄京 8

ServiceWorker是在后台运行的一条服务Worker线程,上海体育场合笔者开了四个标签页,所以显得了五个Client,可是不管开多少个页面都只有四个Worker在负担管理。这几个Worker的干活是把部分财富缓存起来,然后拦截页面包车型大巴恳求,先看下缓存Curry有没有,假诺有的话就从缓存里取,响应200,反之未有的话就走正规的伸手。具体来讲,ServiceWorker结合Web App Manifest能到位以下职业(那也是PWA的检测专门的工作):

澳门新萄京 9

席卷能够离线使用、断网时重回200、能提示顾客把网址增添一个Logo到桌面上等。

加紧效果

首页加速后,网络要求从16降为1,加载时间从2.296s降为0.654s,获得了眨眼之间间加载的结果。

澳门新萄京 10

基于webpagetest

查看测验结果

Service Worker的生命周期

Service worker具有贰个完全部独用立于Web页面包车型地铁生命周期。

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

在装置进度中,浏览器会加载并缓存一些静态财富。要是具备的公文被缓存成功,service worker就设置成功了。假若有别的文件加载或缓存退步,那么安装进程就能够倒闭,service worker就无法被激活(也即未能安装成功)。若是爆发这么的标题,别顾忌,它会在下一次再品尝安装。

当安装完结后,service worker的下一步是激活,在这一等级,你还能升官一个service worker的版本,具体内容大家会在后头讲到。

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

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

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

澳门新萄京 11

举办阅读

别的,还应该有多少个很棒的离线成效案例。如:Guardian 创设了八个全体 crossword puzzle(填字游戏)的离线 web 页面 – 因而,纵然等待网络重连时(即已在离线状态下),也能找到一点乐趣。我也引入看看 Google Chrome Github repo,它含有了多数差别的 Service Worker 案例 – 个中有的行使案例也在那!

不过,要是你想跳过上述代码,只是想大约地因此贰个库来拍卖相关操作,那么作者引入您看看 UpUp。那是一个轻量的剧本,能令你更自在地行使离线效能。

打赏援救作者翻译更加的多好小说,谢谢!

打赏译者

干活原理

因此一段轻巧的 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的文章。

打赏援救笔者翻译更加多好小说,感激!

打赏译者

2. Service Worker的支撑情形

Service Worker近日独有Chrome/Firfox/Opera帮衬:

澳门新萄京 12

Safari和Edge也在备选协理Service Worker,由于瑟维斯Worker是谷歌(Google)中央的一项正式,对于生态比较密封的Safari来讲也是迫于时势先河盘算辅助了,在Safari TP版本,能够见见:

澳门新萄京 13

在试验功效(Experimental Features)里已经有ServiceWorker的菜单项了,只是尽管展开也是不可能用,会提醒您还尚无落实:

澳门新萄京 14

但不论怎么,最少评释Safari已经筹算扶助ServiceWorker了。别的还足以看来在今年二零一七年四月宣布的Safari 11.0.1本子现已支撑WebRTC了,所以Safari依旧多少个前行的孩子。

Edge也策画帮忙,所以Service Worker的前景特别美好。

加速/离线原理探寻

在我们开首写码在此之前

从这个类型地址拿到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摸底最好试行。

打赏扶助小编翻译更加多好小说,感谢!

任选一种支付办法

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

1 赞 3 收藏 1 评论

打赏辅助自身翻译越多好小说,谢谢!

澳门新萄京 17

1 赞 收藏 评论

3. 使用Service Worker

瑟维斯Worker的选拔套路是先挂号一个Worker,然后后台就能够运营一条线程,可以在那条线程运转的时候去加载一些能源缓存起来,然后监听fetch事件,在这些事件里拦截页面包车型客车央求,先看下缓存里有未有,假使有直接重返,不然寻常加载。大概是一伊始不缓存,各种财富央浼后再拷贝一份缓存起来,然后下一回呼吁的时候缓存里就有了。

什么是 Service worker

澳门新萄京 18

如上图,Service worker 是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当八个页面注册了二个 Service worker,它就可以挂号一多元事件处理器来响应如网络恳求和音信推送那些事件。Service worker 能够被用来管理缓存,当响应贰个网络诉求时得以安顿为回到缓存照旧从网络获取。由于Service worker 是根据事件的,所以它只在管理这么些事件的时候被调入内部存款和储蓄器,不用操心常驻内部存款和储蓄器占用能源导致系统变慢。

使用Service Worker

今昔我们有了polyfill,而且解决了HTTPS,让我们看看见底怎么用service worker。

关于笔者:刘健超-J.c

澳门新萄京 19

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

澳门新萄京 20

有关小编:Erucy

澳门新萄京 21

现已的SharePoint喵星技士(权且还挂着微软MVP的名头),未来的Azure/.Net/MongoDB/Cordova/前端技士,不时写小说 个人主页 · 我的篇章 · 46 ·   

澳门新萄京 22

(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同样是有Path路线的定义的,假如你设定三个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)瑟维斯 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

瑟维斯Worker的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的垄断(monopoly)从第三回页面访谈发轫

在第一遍加载页面时,全数财富都以从网络载的,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都一样才是同样的能源,能够设定第贰个参数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版本能够观察地面存款和储蓄的台湾空中大学壮接纳景况:

澳门新萄京 29

个中Cache Storage是指ServiceWorker和Manifest占用的上空尺寸和,上海体育场地能够看出总的空间大小是20GB,大概是unlimited,所以基本上不用顾虑缓存会非常不足用。

特点

  • 浏览器

谷歌 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是在页面注册的,不过未来获取页面包车型地铁时候是从缓存取的,每回没什么分歧的,所以就招致无可奈何立异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猎豹CS6L(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: []}}

当中根本有三个update提姆e的字段,倘若当地内部存款和储蓄器未有那个页面包车型客车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却又是足以的。

综上,本文介绍了怎么用瑟维斯 Worker结合Manifest做三个PWA离线Web 应用软件,首固然用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能够调节网址有着的页面,,同理,假使把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()前段时间仅帮助瑟维斯 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的行事更像其余的CO帕杰罗S央求,比方<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

fetch

JavaScript

//////// // Fetch //////// function onFetch(event) { const request = event.request; if (shouldAlwaysFetch(request)) { event.respondWith(networkedOrOffline(request)); return; } if (shouldFetchAndCache(request)) { event.respondWith(networkedOrCached(request)); return; } event.respondWith(cachedOrNetworked(request)); } onFetch做为浏览器网络央浼的代理,依照供给回到网络或缓存内容,纵然获得了互联网内容,再次来到网络央求时还要开展缓存操作。

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

Non-CO奔驰M级S暗许不帮忙

默许景况下,从第三方UEscortL跨域获得五个财富将会失利,除非对方援救了COCRUISERS。你能够加上八个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

模仿断网状态

  • 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/

能够看来已经有23个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

本文由澳门新萄京发布于澳门新萄京最大平台,转载请注明出处:澳门新萄京连不上网,创建一个非常简单的离线

上一篇:澳门新萄京rem布局原理,教会你开发移动端页面 下一篇:没有了
猜你喜欢
热门排行
精彩图文