离线访问静态blog网站

使用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上独具这几个功用成为大概。

增长速度/离线访问只需三步

  • 首页增多注册代码

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都援用了什么样第三方能源,每种加到忽略列表里。

澳门新葡亰平台官网 1

在根目录下增加offline.html,在未有互连网且缓存中也没偶然利用,效果如下:

澳门新葡亰平台官网 2

在根目录下增添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,那你必要先读书这篇文章。

加速效果

首页加速后,互连网恳求从16降为1,加载时间从2.296s降为0.654s,获得了一晃加载的结果。

澳门新葡亰平台官网 3

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

澳门新葡亰平台官网 4

加紧/离线原理探究

在大家开头写码在此以前

从这个品种地址拿到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明白最棒施行。

什么是 Service worker

澳门新葡亰平台官网 5

如上图,Service
worker

是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当叁个页面注册了一个
Service
worker
,它就能够登记一种类事件管理器来响应如互联网诉求和新闻推送那个事件。Service
worker

能够被用来治本缓存,当响应三个互连网哀求时能够配备为回去缓存照旧从互联网获取。由于Service
worker

是依赖事件的,所以它只在管理那么些事件的时候被调入内部存款和储蓄器,不用顾虑常驻内部存款和储蓄器占用能源导致系统变慢。

使用Service Worker

明日大家有了polyfill,何况搞定了HTTPS,让大家看看究竟怎么用service
worker。

Service worker生命周期

澳门新葡亰平台官网 6

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

澳门新葡亰平台官网 7

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

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

Service worker的支配从第三次页面采访起先

在第叁次加载页面时,全体财富都以从网络载的,Service
worker

在第三次加载时不会赢得调控网络响应,它只会在后续访谈页面时起效果。

澳门新葡亰平台官网 8

页面第一回加载时成功install,并跻身idle状态。

澳门新葡亰平台官网 9

页面第三次加载时,进入activated状态,图谋管理全体的风浪,同时
浏览器会向服务器发送一个异步 央浼来检查Service
worker
自身是还是不是有新的版本,构成了Service
worker
的翻新机制。

澳门新葡亰平台官网 10

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能垄断(monopoly)它所加载的满贯范围内的财富。

  • 不能够操作DOM

跟DOM所处的条件是并行隔开的。

澳门新葡亰平台官网 11

  • 未有浏览页面时也得以运营

收纳系统事件,后台运行

  • 事件驱动,须要时运维,无需时就止住

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

  • 可升级

实践时会异步获取最新的版本

哪些缓存和重返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只好被读取三次,所以大家得将它克隆出来,一份发给浏览器,一份发给缓存。

万事如意加速/离线

怎样翻新一个瑟维斯 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

–本文的主人公。

管理边界和填坑

这一节内容比较新,有过多待定细节。希望这一节相当慢就不供给讲了(因为标准会处理那一个难题——译者注),可是今后,这几个内容照旧应该被提一下。

发表评论

电子邮件地址不会被公开。 必填项已用*标注