菜单

使用Service worker实现加快/离线访问静态blog网址

2019年4月15日 - Html/Html5

选拔Service worker达成加速/离线访问静态blog网址

2017/02/19 · JavaScript
· Service Worker

原稿出处: Yang
Bo
   

manbetx2.0手机版,后日很盛行基于Github
page和markdown的静态blog,非凡适合技术的思辨和习惯,针对差异的言语都有部分妙不可言的静态blog系统出现,如Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于静态内容的特征格外适合做缓存来加速页面包车型大巴拜会,就动用Service
worker
来兑现加速,结果是除了PageSpeed,CDN那几个科普的服务器和网络加速之外,通过客户端达成了越来越好的走访体验。

动用 Service worker 创造二个非凡不难的离线页面

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

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

让大家想像以下情况:大家那时候在1辆通往农村的列车上,用运动装备看着1篇很棒的稿子。与此同时,当你点击“查看越多”的链接时,高铁忽然进入了隧道,导致移动设备失去了互联网,而
web 页面会展现出类似以下的始末:

manbetx2.0手机版 1

那是一定令人失落的感受!幸运的是,web
开发者们能透过有个别新性格来立异那类的用户体验。笔者近年一贯在折腾 ServiceWorkers,它给 web 带来的无尽恐怕性总能给本人惊喜。Service Workers
的名特别优惠特质之壹是同意你检查评定网络请求的现象,并让你作出相应的响应。

在那篇小说里,小编打算用此特性检查用户的最近互连网连接景况,假设没连接则赶回1个至上简单的离线页面。即便那是一个可怜基础的案例,但它能给你带来启迪,让您驾驭启动并运维该个性是何等的简要!假设你没理解过
Service Worker,笔者提出您看看此 Github
repo
,驾驭更加多相关的音讯。

在此案例开头前,让大家先简单地看望它的工作流程:

  1. 在用户第叁回访问大家的页面时,大家会安装 ServiceWorker,并向浏览器的缓存添加大家的离线 HTML 页面
  2. 然后,借使用户打算导航到另三个 web
    页面(同3个网址下),但此时已断网,那么大家将再次回到已被缓存的离线
    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>

https://alphayang.github.io/sw.js封存到您的网址根目录下

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

manbetx2.0手机版 2

在根目录下添加offline.html,在未曾互连网且缓存中也未有时利用,效果如下:

manbetx2.0手机版 3

在根目录下添加offline.svg,在无网络时图片财富请求重回该文件。

让大家初叶吧

比方你有以下 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。倘诺您的缓存有两样版本,那么你只需革新版本号即可不难地排除缓存。在大体在第一贰行代码,作者向那么些离线页面及其能源(如:图片)发出请求。在获得成功的响应后,大家将离线页面和连锁能源丰盛到缓存。

现行反革命,离线页面已存进缓存了,大家可在供给的时等候检查索它。在同三个 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 访问互连网)

manbetx2.0手机版 4

若是你刷新页面,你应当能收占星应的离线页面!

manbetx2.0手机版 5

借使你只想大约地质衡量试该意义而不想写任何代码,那么您可以访问作者已成立好的
demo。其它,上述任何代码能够在
Github repo 找到。

本身明白用在此案例中的页面很简短,但您的离线页面则在于你协调!假使你想深远该案例的内容,你能够为离线页面添加缓存破坏(
cache busting),如:
此案例

加快效果

首页加快后,网络请求从1陆降为一,加载时间从二.296s降为0.65四s,获得了一晃加载的结果。

manbetx2.0手机版 6

基于webpagetest

查看测试结果

拓展阅读

其它,还有多少个很棒的离线作用案例。如:Guardian 营造了3个有着 crossword
puzzle
(填字游戏)的离线
web 页面 –
因此,尽管等待互连网重连时(即已在离线状态下),也能找到一点乐趣。小编也援引看看
Google Chrome Github
repo
,它含有了很多不等的
Service Worker 案例 – 在那之中有的用到案例也在那!

只是,要是您想跳过上述代码,只是想大致地通过二个库来处理有关操作,那么作者引入你看看
UpUp。那是叁个轻量的台本,能让您更自在地行使离线成效。

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


打赏译者

增长速度/离线原理探索

打赏扶助自个儿翻译越多好文章,感谢!

任选1种支付情势

manbetx2.0手机版 7
manbetx2.0手机版 8

1 赞 3 收藏 1
评论

什么是 Service worker

manbetx2.0手机版 9

如上图,Service
worker

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

能够被用来治本缓存,当响应一个互联网请求时方可布署为回去缓存还是从互连网得到。由于Service
worker

是依照事件的,所以它只在拍卖那几个事件的时候被调入内部存款和储蓄器,不用顾虑常驻内部存款和储蓄器占用财富导致系统变慢。

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

manbetx2.0手机版 10

前端,在路上…http://jchehe.github.io
个人主页
·
作者的篇章
·
19
·
    

manbetx2.0手机版 11

Service worker生命周期

manbetx2.0手机版 12

Service
worker

为网页添加一个好像于APP的生命周期,它只会响应系统事件,纵然浏览器关闭时操作系统也足以唤起Service
worker
,那点十分重要,让web
app与native app的能力变得近乎了。

Service
worker
在Register时会触发Install事件,在Install时得以用来预先获取和缓存应用所需的能源并设置各类文件的缓存策略。

一旦Service
worker
地处activated状态,就能够完全控制应用的财富,对互联网请求进行检查,修改网络请求,从网络上取得并重返内容可能再次回到由已设置的Service
worker
预报获取并缓存好的财富,甚至仍能转移内容并回到给互联网语法。

怀有的这几个都用户都以晶莹剔透的,事实上,三个安排精良的Service
worker
就像3个智能缓存系统,坚实了互联网和缓存效能,选用最优办法来响应互连网请求,让使用尤其稳定的运行,固然没有网络也没提到,因为你能够完全控制网络响应。

Service worker的决定从第三回页面访问先导

在第二遍加载页面时,全体能源都以从网络载的,Service
worker

在第一回加载时不会博得控制互联网响应,它只会在继承访问页面时起作用。

manbetx2.0手机版 13

页面第三回加载时做到install,并跻身idle状态。

manbetx2.0手机版 14

页面第三遍加载时,进入activated状态,准备处理全数的事件,同时
浏览器会向服务器发送1个异步 请求来检查Service
worker
自家是还是不是有新的版本,构成了Service
worker
的立异机制。

manbetx2.0手机版 15

Service
worker
处理完全体的风浪后,进入idle状态,最后进入terminated状态财富被放出,当有新的事件发生时再一次被调用。

特点

谷歌(Google) Chrome,Firefox,Opera以及境内的各样双核浏览器都支持,可是 safari
不帮忙,那么在不帮忙的浏览器里Service
worker
不工作。

网址必须启用https来担保使用Service
worker
页面包车型地铁安全性,开发时localhost私下认可认为是高枕无忧的。

Service
worker

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

Service
worker
运转在大团结的大局环境中,平日也运转在温馨独自的线程中。

service work能决定它所加载的任何范围内的财富。

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

manbetx2.0手机版 16

收受系统事件,后台运营

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

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

达成加速/离线

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);
    });

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);

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

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做为浏览器网络请求的代理,根据需要返回网络或缓存内容,如果获取了网络内容,返回网络请求时同时进行缓存操作。

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值来删除过期的缓存。

管理 Service worker

特定网址

  1. Google Chrome

Developer Tools->Application->Service Workers

manbetx2.0手机版 17

在这边还有五个尤其实惠的复选框:

仿照断网状态

  1. Firefox

唯有在Settings里有一个足以在HTTP环境中利用Service
worker
的选项,适应于调节和测试,未有单独网址下的Service
worker
管理。

manbetx2.0手机版 18

  1. Opera及任何双核浏览器同谷歌 Chrome
    假诺见到多个一样范围内的多少个Service
    worker
    ,说明Service
    woker
    更新后,而原有Service
    worker
    还并未有被terminated。

浏览器全局

探望你的浏览器里都有啥样Service worker已经存在了

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

能够看出已经有二五个Serviceworker了,在那里能够手动Start让它工作,也足以Unregister卸载掉。

manbetx2.0手机版 19

  1. Firefox

有二种艺术进入Service
worker
治本界面来手动Start或unregister。

JavaScript

about:debugging#workers

1
about:debugging#workers

manbetx2.0手机版 20

  1. Opera及其余双核浏览器同谷歌 Chrome

更多

TODO:

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

manbetx2.0手机版 21

相关文章

发表评论

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

网站地图xml地图