原生App具有Web应用一般所不辜负有的富离线体验

2019-09-17 08:30栏目:前端开发
TAG:

应用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 翻译,艾凌风 校稿。未经许可,禁止转载!
立陶宛共和国(Republic of Lithuania)语出处:Dean Hume。应接参与翻译组。

让我们想像以下场景:大家那儿在一辆通往农村的高铁的里面,用移动设备望着一篇很棒的小说。与此相同的时候,当您点击“查看愈来愈多”的链接时,轻轨骤然进入了隧道,导致运动器具失去了网络,而 web 页面会突显出类似以下的内容:

图片 1

这是格外让人心寒的感受!幸运的是,web 开采者们能因此一些新特色来革新这类的顾客体验。笔者多年来平素在折腾 ServiceWorkers,它给 web 带来的数不尽或然性总能给自个儿惊奇。Service Workers 的好好特质之一是允许你检查评定网络诉求的光景,并让您作出相应的响应。

在那篇文章里,小编绸缪用此性情检查顾客的日前网络连接处境,假设没连接则赶回三个特级轻巧的离线页面。就算这是八个丰富基础的案例,但它能给您带来启发,令你精晓运维并运营该个性是何其的简约!假使您没掌握过 Service Worker,小编提出你看看此 Github repo,领悟越多相关的音讯。

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

  1. 在客户第贰遍访谈大家的页面时,我们会安装 ServiceWorker,并向浏览器的缓存增多大家的离线 HTML 页面
  2. 接下来,假若客户筹划导航到另一个 web 页面(同八个网址下),但那时已断网,那么大家将回到已被缓存的离线 HTML 页面
  3. 而是,倘诺顾客准备导航到其他三个 web 页面,而此刻互联网已再三再四,则能照常浏览页面

加紧/离线访谈只需三步

  • 首页增加注册代码

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都引用了怎么第三方财富,每一种加到忽略列表里。

图片 2

在根目录下增多offline.html,在一贯不互连网且缓存中也没偶尔采用,效果如下:

图片 3

在根目录下增多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 访谈互连网)

图片 4

借使您刷新页面,你应当能收六柱预测应的离线页面!

图片 5

倘若您只想大约地质度量试该意义而不想写任何代码,那么你能够访谈我已开立好的 demo。其他,上述所有代码能够在 Github repo 找到。

自身精晓用在此案例中的页面很粗大略,但你的离线页面则取决于你本人!若是您想深远该案例的剧情,你可以为离线页面增多缓存破坏( cache busting),如: 此案例。

增长速度效果

首页加快后,网络诉求从16降为1,加载时间从2.296s降为0.654s,得到了一下加载的结果。

图片 6

基于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初次安装的生命周期:

图片 7

举行阅读

其它,还应该有多少个很棒的离线作用案例。如:Guardian 营造了贰个享有 crossword puzzle(填字游戏)的离线 web 页面 – 由此,尽管等待网络重连时(即已在离线状态下),也能找到一点野趣。笔者也援用看看 Google Chrome Github repo,它包括了众多见仁见智的 Service Worker 案例 – 在那之中一部分利用案例也在这!

可是,倘诺你想跳过上述代码,只是想差不离地通过贰个库来拍卖相关操作,那么本人引入您看看 UpUp。那是一个轻量的脚本,能令你更自在地采纳离线效能。

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

打赏译者

加速/离线原理探求

在大家初阶写码以前

从这个品类地址拿到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摸底最佳实行。

打赏协助本人翻译越来越多好作品,多谢!

任选一种支付格局

图片 8 图片 9

1 赞 3 收藏 1 评论

什么是 Service worker

图片 10

如上图,Service worker 是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当一个页面注册了两个 Service worker,它就可以挂号一名目大多事件管理器来响应如互联网央求和新闻推送那几个事件。Service worker 能够被用来管理缓存,当响应三个互联网央浼时方可配备为回去缓存依然从网络获得。由于Service worker 是依据事件的,所以它只在拍卖这么些事件的时候被调入内部存储器,不用操心常驻内部存款和储蓄器占用能源导致系统变慢。

使用Service Worker

方今咱们有了polyfill,而且解决了HTTPS,让大家看看毕竟怎么用service worker。

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

图片 11

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

图片 12

Service worker生命周期

图片 13

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

图片 14

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

您会发觉那几个效果可以相当的低价地在多个模仿窗口中测验你的service worker,这样您可以关闭和重新打开它,而不会影响到你的新窗口。任何创立在模拟窗口中的注册服务和缓存在窗口被关闭时都将未有。

Service worker的主宰从第三回页面访谈开头

在第二回加载页面时,全部财富都以从互连网载的,Service worker 在第一遍加载时不会获得调节网络响应,它只会在后续访问页面时起效果。

图片 15

页面第一回加载时产生install,并走入idle状态。

图片 16

页面第3回加载时,步入activated状态,筹划管理所有的平地风波,同时 浏览器会向服务器发送多个异步 哀求来检查Service worker自己是或不是有新的版本,构成了Service worker的立异机制。

图片 17

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事件。

特点

  • 浏览器

Google Chrome,Firefox,Opera以及境内的各样双核浏览器都帮助,可是 safari 不接济,那么在不协助的浏览器里Service worker不工作。

  • https

网址必需启用https来担保使用Service worker页面的安全性,开辟时localhost暗中认可认为是安全的。

  • non-block

Service worker 中的 Javascript 代码必得是非阻塞的,因为 localStorage 是阻塞性,所以不该在 Service Worker 代码中利用 localStorage。

  • 独自的实行碰到

Service worker运维在大团结的大局情形中,常常也运营在温馨独自的线程中。

  • 并未有绑定到一定页面

service work能调整它所加载的万事范围内的财富。

  • 无法操作DOM

跟DOM所处的条件是互为隔开的。

图片 18

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

收到系统事件,后台运转

  • 事件驱动,须求时运营,无需时就停止

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

  • 可升级

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

怎么着缓存和重返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只可以被读取二遍,所以大家得将它克隆出来,一份发给浏览器,一份发给缓存。

落到实处加速/离线

什么样立异多少个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);
          }
        })
      );
    })
  );
});

Cache

网页缓存有无数,如HTTP缓存,localStorage,sessionStorage和cacheStorage都可以灵活搭配进行缓存,但操作太繁琐,间接利用更加尖端Service worker –本文的庄家。

拍卖边界和填坑

这一节内容相比较新,有繁多待定细节。希望这一节非常的慢就无需讲了(因为标准会管理这一个主题材料——译者注),然而今后,这么些故事情节照旧应当被提一下。

添加Service worker入口

在web app的首页加多以下代码

JavaScript

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

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

要是浏览器援助serviceWorker就注册它,不帮助依然正常浏览,未有Service worker所提供的进步功效。

Service worker调节范围:
总结情形下,将sw.js坐落网址的根目录下,这样Service worker能够调控网址有着的页面,,同理,如若把sw.js放在/my-app/sw.js那正是说它只好调整my-app目录下的页面。
sw.js放在/js/目录呢?更加好的目录结议和范围调整呢?
在注册时钦定js地方并设置限制。

JavaScript

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

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

即便设置战败了,未有很优雅的点子赢得通报

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

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

Service worker实现

监听四个事件:

JavaScript

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

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

fetch()近期仅帮衬Service Workers

fetch立刻补助在页面上采纳了,不过当前的Chrome实现,它还只辅助service worker。cache API也即就要页面上被协助,不过近年来甘休,cache也还不得不在service worker中用。

install

JavaScript

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

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

install时将具备符合缓存战略的财富扩充缓存。

fetch()的暗中同意参数

当您使用fetch,缺省地,必要不会带上cookies等证据,要想带上的话,供给:

JavaScript

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

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

如此设计是有理由的,它比XH大切诺基的在同源下私下认可发送凭据,但跨域时扬弃凭据的平整要来得好。fetch的一坐一起更像任何的COEnclaveS诉求,比方<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科雷傲S暗许不援助

暗许情形下,从第三方U卡宴L跨域获得二个财富将会退步,除非对方支持了COEscortS。你能够增长贰个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;" />

图片 19

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

特定网址

  1. Google Chrome

Developer Tools->Application->Service Workers

图片 20

在此间还应该有多个要命管用的复选框:

  • Offline

模仿断网状态

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

唯有在Settings里有四个能够在HTTP情状中运用Service worker的选项,适应于调试,未有单独网站下的Service worker管理。

图片 21

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

改变URL Hash的Bug

在M40版本中留存三个bug,它会让页面在改造hash的时候变成service worker结束专门的职业。

你能够在此间找到更多相关的新闻: 

浏览器全局

探望您的浏览器里都有何瑟维斯 worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

能够见见已经有22个Serviceworker了,在此间能够手动Start让它专业,也得以Unregister卸载掉。

图片 22

  1. Firefox

有三种艺术步入Service worker处理分界面来手动Start或unregister。

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

JavaScript

about:debugging#workers

1
about:debugging#workers

图片 23

  1. Opera及别的双核浏览器同Google Chrome

越来越多内容

那边有局地相关的文书档案能够参考:

更多

TODO:

  • Service workers的换代要求手动编辑version,每一次发表新小说时需求编写制定。
  • 使用AMP让页面渲染速度高达最高。

取得帮衬

一旦你遇见麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于我们即刻跟进和尽可能支持您化解难题。

赞 2 收藏 评论

图片 24

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

图片 25

版权声明:本文由大奖888-www.88pt88.com-大奖888官网登录发布于前端开发,转载请注明出处:原生App具有Web应用一般所不辜负有的富离线体验