大不列颠及英格兰联合王国卫报的天性离线页面

时间:2019-10-09 05:21来源:网页制作
Service Worker初体验 2016/01/06 · JavaScript· Service Worker 原稿出处: AlloyTeam    在2014年,W3C宣布了service worker的草案,serviceworker提供了相当多新的力量,使得web app具备与nativeapp一样的离线体

Service Worker初体验

2016/01/06 · JavaScript · Service Worker

原稿出处: AlloyTeam   

在2014年,W3C宣布了service worker的草案,service worker提供了相当多新的力量,使得web app具备与native app一样的离线体验、新闻推送体验。
service worker是一段脚本,与web worker同样,也是在后台运转。作为三个单独的线程,运转条件与经常脚本差异,所以无法直接参加web交互行为。native app能够成功离线使用、新闻推送、后台自动更新,service worker的面世是幸而为了使得web app也能够具备类似的力量。

 

service worker可以:

  1. 后台音信传递
  2. 网络代理,转载呼吁,伪造响应
  3. 离线缓存
  4. 音讯推送
  5.  … …

本文以能源缓存为例,说飞鹤下service worker是何等工作的。

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

2015/11/20 · HTML5 · Service Worker, 离线页面

本文由 伯乐在线 - Erucy 翻译,weavewillg 校稿。未经许可,幸免转发!
意大利语出处:Oliver Ash。招待参加翻译组。

我们是什么样利用 service worker 来为 theguardian.com 创设三个自定义的离线页面。

图片 1

theguardian.com 的离线页面。插图:奥利弗 Ash

您正在朝着集团途中的客车里,在堂哥大上开采了 Guardian 应用。地铁被隧道包围着,可是那一个利用能够符合规律运转,就算未有互连网连接,你也能获取完全的法力,除了突显的内容也有一点旧。如若您品味在网址上也这么干,可惜它完全没有办法加载:

图片 2

安卓版 Chrome 的离线页面

Chrome 中的这么些彩蛋,很几个人都不知道》

Chrome 在离线页面上有个藏匿的玩乐(桌面版上按空格键,手提式有线电话机版上点击那只恐龙),那有一些能减轻一点您的烦扰。但是大家能够做得越来越好。

Service workers 允许网址作者拦截自身站点的具有互连网央浼,那也就代表大家得以提供周全的离线体验,就如原生应用一样。在 Guardian 网址,大家多年来上线了贰个自定义的离线体验效果。当客商离线的时候,他们会看出三个包含Guardian 标志的页面,上边带有四个简易的离线提示,还应该有三个填字游戏,他们能够在等待网络连接的时候玩玩那些找点乐子。那篇博客解释了大家是哪些构建它的,可是在开班此前,你能够先自身尝试看。

生命周期

先来看一下四个service worker的运转周期

图片 3
上图是service worker生命周期,出处

图中可以见见,贰个service worker要经历以下进程:

  1.  安装

2.  激活,激活成功之后,展开chrome://inspect/#service-workers能够查阅到最近运营的service worker

图片 4

  1. 监听fetch和message事件,上面三种事件博览会开简要描述

  2. 销毁,是或不是销毁由浏览器决定,如若一个service worker长期不接纳依然机器内存有数,则恐怕会销毁这一个worker

试试看

你必要一个支撑 Service Worker 和 fetch API 的浏览器。截至到本文编写时唯有Chrome(手提式有线话机版和桌面版)同不时候支持那三种 API(译者注:Opera 前段时间也支撑这两边),可是 Firefox 异常的快就要援助了(在每一日更新的版本中早已支撑了),除此而外 Safari 之外的具有浏览器也都在实施。其它,service worker 只可以登记在应用了 HTTPS 的网站上,theguardian.com 已经起来逐步搬迁到 HTTPS,所以大家不得不在网址的 HTTPS 部分提供离线体验。就现阶段的话,我们挑选了 开拓者博客 作为大家用来测量试验的地点。所以即便你是在我们网站的 开辟者博客 部分阅读那篇文章的话,很幸运。

当您使用协助的浏览器访谈大家的 开垦者博客 中的页面包车型地铁时候,一切就计划妥善了。断开你的网络连接,然后刷新一下页面。假若你和谐没标准尝试的话,能够看一下这段 演示录制(译者注:需梯子)。

fetch事件

在页面发起http供给时,service worker能够经过fetch事件拦截哀告,何况付诸本身的响应。
w3c提供了三个新的fetch api,用于代替XMLHttpRequest,与XMLHttpRequest最大不相同有两点:

1. fetch()方法再次来到的是Promise对象,通过then方法举行连接调用,减弱嵌套。ES6的Promise在改为规范之后,会越来越便利开辟人士。

2. 提供了Request、Response对象,就算做过后端开荒,对Request、Response应该比较熟谙。前端要提倡呼吁能够经过url发起,也得以行使Request对象发起,并且Request能够复用。可是Response用在何地啊?在service worker出现在此之前,前端确实不会和睦给协和发消息,但是有了service worker,就足以在阻止诉求之后听他们说要求发回自个儿的响应,对页面来说,那么些普通的央求结果并不曾分裂,那是Response的一处选用。

下边是在中,笔者利用fetch api通过fliker的当众api获取图片的事例,注释中详细分解了每一步的意义:

JavaScript

/* 由于是get央浼,直接把参数作为query string传递了 */ var URL = ''; function fetchDemo() { // fetch(url, option)援救四个参数,option中得以安装header、body、method新闻fetch(UTiggoL).then(function(response) { // 通过promise 对象得到对应内容,并且将响应内容依据json格式转成对象,json()方法调用之后回来的依然是promise对象 // 也足以把内容转化成arraybuffer、blob对象 return response.json(); }).then(function(json) { // 渲染页面 insertPhotos(json); }); } fetch德姆o();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 由于是get请求,直接把参数作为query string传递了 */
var URL = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=your_api_key&format=json&nojsoncallback=1&tags=penguins';
 
function fetchDemo() {
  // fetch(url, option)支持两个参数,option中可以设置header、body、method信息
  fetch(URL).then(function(response) {
    // 通过promise 对象获得相应内容,并且将响应内容按照json格式转成对象,json()方法调用之后返回的依然是promise对象
    // 也可以把内容转化成arraybuffer、blob对象
    return response.json();
  }).then(function(json) {
    // 渲染页面
    insertPhotos(json);
  });
}
 
fetchDemo();

fetch api与XMLHttpRequest相比较,越发简洁,而且提供的功效更完美,财富得到格局比ajax更温婉。包容性方面:chrome 42起来援救,对于旧浏览器,能够经过合法维护的polyfill帮忙。

干活原理

经过一段轻松的 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 很感兴趣,想要驾驭越多内容的话,开荒者 马特Gaunt(Chrome的忠贞协理者)写了一篇尤其详细地 介绍 Service Worker的文章。

打赏帮助作者翻译越多好作品,多谢!

打赏译者

message事件

页面和serviceWorker之间能够经过posetMessage()方法发送音信,发送的音讯能够透过message事件接收到。

那是三个双向的经过,页面能够发音信给service worker,service worker也得以发送新闻给页面,由于这些个性,能够将service worker作为中间纽带,使得一个域名依旧子域名下的多个页面能够私自通讯。

此间是多少个小的页面之间通讯demo

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

图片 5

1 赞 收藏 评论

动用service workder缓存文件

上边介绍贰个用到service worker缓存离线文件的例证
预备index.js,用于注册service-worker

JavaScript

if (navigator.serviceWorker) { navigator.serviceWorker.register('service-worker.js').then(function(registration) { console.log('service worker 注册成功'); }).catch(function (err) { console.log('servcie worker 注册退步') }); }

1
2
3
4
5
6
7
if (navigator.serviceWorker) {
    navigator.serviceWorker.register('service-worker.js').then(function(registration) {
        console.log('service worker 注册成功');
    }).catch(function (err) {
        console.log('servcie worker 注册失败')
    });
}

在上述代码中,注册了service-worker.js作为当前路线下的service worker。由于service worker的权柄相当高,全部的代码都亟待是安全可相信的,所以唯有https站点手艺够使用service worker,当然localhost是七个特例。
登记结束,未来开端写service-worker.js代码。
依照后边的生命周期图,在一个新的service worker被注册之后,首先会触发install事件,在service-workder.js中,能够透过监听install事件开展部分初阶化工作,大概哪些也不做。
因为大家是要缓存离线文件,所以能够在install事件中初叶缓存,可是只是将文件加到caches缓存中,真正想让浏览器选取缓存文件需求在fetch事件中阻止

JavaScript

var cacheFiles = [ 'about.js', 'blog.js' ]; self.addEventListener('install', function (evt) { evt.waitUntil( caches.open('my-test-cahce-v1').then(function (cache) { return cache.addAll(cacheFiles); }) ); });

1
2
3
4
5
6
7
8
9
10
11
var cacheFiles = [
    'about.js',
    'blog.js'
];
self.addEventListener('install', function (evt) {
    evt.waitUntil(
        caches.open('my-test-cahce-v1').then(function (cache) {
            return cache.addAll(cacheFiles);
        })
    );
});

第一定义了供给缓存的公文数组cacheFile,然后在install事件中,缓存那个文件。
evt是贰个Install伊夫nt对象,继承自Extendable伊夫nt,在这之中的waitUntil()方法接收四个promise对象,直到那么些promise对象成功resolve之后,才会延续运营service-worker.js。
caches是一个CacheStorage对象,使用open()方法张开二个缓存,缓存通过名称实行区分。
赢得cache实例之后,调用addAll()方法缓存文件。

那样就将文件增多到caches缓存中了,想让浏览器采纳缓存,还亟需拦截fetch事件

JavaScript

// 缓存图片 self.add伊夫ntListener('fetch', function (evt) { evt.respondWith( caches.match(evt.request).then(function(response) { if (response) { return response; } var request = evt.request.clone(); return fetch(request).then(function (response) { if (!response && response.status !== 200 && !response.headers.get('Content-type').match(/image/)) { return response; } var responseClone = response.clone(); caches.open('my-test-cache-v1').then(function (cache) { cache.put(evt.request, responseClone); }); return response; }); }) ) });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 缓存图片
self.addEventListener('fetch', function (evt) {
    evt.respondWith(
        caches.match(evt.request).then(function(response) {
            if (response) {
                return response;
            }
            var request = evt.request.clone();
            return fetch(request).then(function (response) {
                if (!response && response.status !== 200 && !response.headers.get('Content-type').match(/image/)) {
                    return response;
                }
                var responseClone = response.clone();
                caches.open('my-test-cache-v1').then(function (cache) {
                    cache.put(evt.request, responseClone);
                });
                return response;
            });
        })
    )
});

由此监听fetch事件,service worker能够再次来到自身的响应。

首先检缓存中是或不是已经缓存了那个央求,假如有,就一贯回到响应,就收缩了三回网络央求。不然由service workder发起央浼,那时的service workder起到了叁个中档代理的职能。

service worker央浼的长河通过fetch api达成,获得response对象以往举办过滤,查看是还是不是是图片文件,假如不是,就径直重临央求,不会缓存。

假设是图形,要先复制一份response,原因是request大概response对象属于stream,只可以选用一次,之后一份存入缓存,另一份发送给页面。
那便是service worker的强大之处:拦截央求,伪造响应。fetch api在此间也起到了一点都不小的功能。

 

service worker的创新很简短,只要service-worker.js的公文内容有创新,就能够使用新的剧本。不过有少数要介意:旧缓存文件的清除、新文件的缓存要在activate事件中开展,因为也许旧的页面还在采纳在此以前的缓存文件,清除之后会失去意义。

 

在第一使用service worker的历程中,也遭受了一部分难点,下边是中间多个

有关小编:Erucy

图片 6

业已的SharePoint喵星技士(暂时还挂着微软MVP的名头),今后的Azure/.Net/MongoDB/Cordova/前端程序员,临时写小说 个人主页 · 作者的文章 · 46 ·   

图片 7

难题1. 运营时刻

service worker并非一贯在后台运维的。在页面关闭后,浏览器可以一连维持service worker运转,也足以关闭service worker,那决计于与浏览器本人的一言一动。所以不用定义一些全局变量,举例上边包车型地铁代码(来自):

JavaScript

var hitCounter = 0; this.addEventListener('fetch', function(event) { hitCounter++; event.respondWith( new Response('Hit number ' + hitCounter) ); });

1
2
3
4
5
6
7
8
var hitCounter = 0;
 
this.addEventListener('fetch', function(event) {
  hitCounter++;
  event.respondWith(
    new Response('Hit number ' + hitCounter)
  );
});

回去的结果也许是一直不规律的:1,2,1,2,1,1,2….,原因是hitCounter并不曾平素存在,假若浏览器关闭了它,后一次起步的时候hitCounter就赋值为0了
这么的作业导致调节和测验代码困难,当你更新贰个service worker现在,独有在开荒新页面以往才恐怕选取新的service worker,在调整进程中不常等上一两分钟才会选取新的,相比较抓狂。

难点2. 权力太大

当service worker监听fetch事件之后,对应的呼吁都会经过service worker。通过chrome的network工具,能够观望此类诉求会标注:from service worker。假诺service worker中冒出了难题,会导致全体诉求战败,包罗日常的html文件。所以service worker的代码品质、容错性一定要很好技艺保险web app符合规律运行。

 

参照他事他说加以考察作品:

1. 

2. 

3. 

4. 

5. 

1 赞 3 收藏 评论

图片 8

编辑:网页制作 本文来源:大不列颠及英格兰联合王国卫报的天性离线页面

关键词: