菜单

行使 Service worker 成立一个非常简单的离线页面

2019年9月29日 - Ajax

使用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这个周围的服务器和网络加快之外,通过客户端完成了更加好的探访体验。

运用 瑟维斯 worker 成立一个特轻巧的离线页面

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

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

让大家想像以下场景:大家那儿在一辆通往农村的高铁上,用移动器材望着一篇很棒的篇章。与此同一时候,当你点击“查看更加多”的链接时,火车顿然进入了隧道,导致运动设备失去了网络,而
web 页面会显示出类似以下的内容:

图片 1

那是相当令人寒心的心得!幸运的是,web
开采者们能通过有个别新特征来创新那类的客户体验。作者这段时间直接在折腾 ServiceWorkers,它给 web 带来的不胜枚举恐怕性总能给自家喜悦。Service Workers
的大好特质之一是同意你检查测量检验互连网央求的景色,并令你作出相应的响应。

在那篇小说里,笔者希图用此性格检查顾客的当前互联网连接处境,假如没连接则赶回四个一流级简单的离线页面。就算那是三个不行基础的案例,但它能给您带来启迪,让您精晓运维并运营该性子是多么的简约!假诺您没掌握过
Service Worker,小编建议你看看此 Github
repo
,精晓越来越多相关的新闻。

在此案例开首前,让大家先轻易地探望它的劳作流程:

  1. 在客户第二次访谈大家的页面时,我们会安装 瑟维斯Worker,并向浏览器的缓存添加我们的离线 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>

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都引用了怎样第三方资源,各种加到忽略列表里。

图片 2

在根目录下增添offline.html,在一贯不互联网且缓存中也并没不经常使用,效果如下:

图片 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(‘瑟维斯Worker 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

查看测验结果

拓宽阅读

其它,还应该有多少个很棒的离线功能案例。如:Guardian 营造了三个颇有 crossword
puzzle
(填字游戏)的离线
web 页面 –
由此,就算等待网络重连时(即已在离线状态下),也能找到一点野趣。笔者也援引看看
Google Chrome Github
repo
,它含有了相当多不一的
Service Worker 案例 – 当中有的运用案例也在那!

而是,要是你想跳过上述代码,只是想大致地经过多个库来拍卖相关操作,那么本人引入您看看
UpUp。那是一个轻量的剧本,能让你更自在地应用离线功效。

打赏辅助作者翻译越多好文章,多谢!


打赏译者

增加速度/离线原理探寻

打赏扶助本身翻译更多好作品,多谢!

任选一种支付方式

图片 7
图片 8

1 赞 3 收藏 1
评论

什么是 Service worker

图片 9

如上图,Service
worker

是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当贰个页面注册了三个
Service
worker
,它就足以登记一文山会海事件管理器来响应如网络央求和音讯推送这几个事件。Service
worker

能够被用来治本缓存,当响应二个网络央浼时可以安顿为回去缓存依旧从网络获得。由于Service
worker

是凭借事件的,所以它只在拍卖这么些事件的时候被调入内部存款和储蓄器,不用担忧常驻内存占用能源导致系统变慢。

关于小编:刘健超-J.c

图片 10

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

图片 11

Service worker生命周期

图片 12

Service
worker

为网页加多八个像样于APP的生命周期,它只会响应系统事件,固然浏览器关闭时操作系统也能够提示Service
worker
,那一点至极重要,让web
app与native app的力量变得就如了。

Service
worker
在Register时会触发Install事件,在Install时方可用来预先获取和缓存应用所需的财富并安装各个文件的缓存策略。

一旦Service
worker
远在activated状态,就可以完全调控应用的能源,对互连网恳求进行反省,修改网络诉求,从网络上获得并赶回内容也许重返由已安装的Service
worker
预示获取并缓存好的能源,以至还足以转变内容并再次回到给互联网语法。

怀有的这几个都顾客都是晶莹的,事实上,贰个设计能够的Service
worker
就好像一个智能缓存系统,抓牢了网络和缓存成效,采取最优办法来响应网络哀告,让动用更加的地西泮的周转,就算未有网络也没涉及,因为你能够完全调节互联网响应。

瑟维斯 worker的支配从第二次页面访谈开首

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

在第三次加载时不会拿走调整互联网响应,它只会在承继访问页面时起效果。

图片 13

页面第贰遍加载时成功install,并步入idle状态。

图片 14

页面第一遍加载时,步向activated状态,计划管理全部的平地风波,同时
浏览器会向服务器发送三个异步 须要来检查Service
worker
自个儿是或不是有新的版本,构成了Service
worker
的更新机制。

图片 15

Service
worker
管理完全体的风云后,步入idle状态,最后走入terminated状态能源被放出,当有新的风浪产生时再一次被调用。

特点

Google Chrome,Firefox,Opera以及本国的各样双核浏览器都援助,可是 safari
不帮忙,那么在不辅助的浏览器里Service
worker
不工作。

网址必得启用https来确保使用Service
worker
页面包车型客车安全性,开采时localhost暗许感到是安全的。

Service
worker

中的 Javascript 代码务必是非阻塞的,因为 localStorage
是阻塞性,所以不应有在 瑟维斯 Worker 代码中动用 localStorage。

Service
worker
运转在协和的大局情形中,常常也运行在融洽独自的线程中。

service work能调整它所加载的全套范围内的能源。

跟DOM所处的碰到是相互隔断的。

图片 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

图片 17

在此处还应该有八个特别管用的复选框:

仿照断网状态

  1. Firefox

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

图片 18

  1. Opera及其余双核浏览器同Google Chrome
    一经见到多个一样范围内的七个Service
    worker
    ,说明Service
    woker
    更新后,而原有Service
    worker
    还未有被terminated。

浏览器全局

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

  1. Google Chrome

在地址栏里输入:

JavaScript

chrome://serviceworker-internals/

1
chrome://serviceworker-internals/

能够见到已经有二十三个Serviceworker了,在这里能够手动Start让它工作,也得以Unregister卸载掉。

图片 19

  1. Firefox

有三种艺术步向Service
worker
管制分界面来手动Start或unregister。

JavaScript

about:debugging#workers

1
about:debugging#workers

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

图片 21

相关文章

发表评论

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

网站地图xml地图