英国卫报的个性离线页面是这样做的

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

原稿出处: Matt
Gaunt   译文出处:[w3ctech

  • 拾年踪迹]()   

原生App具有Web应用普通所不持有的富离线体验,按期的沉吟不语更新,新闻布告推送等作用。而新的Serviceworkers标准让在Web App上具备那么些成效成为大概。

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

初稿出处: AlloyTeam   

在201四年,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是何等职业的。

连不上网?United Kingdom卫报的特性离线页面是那样做的

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
标志的页面,上面带有二个简单易行的离线提示,还有2个填字游戏,他们能够在等候互联网连接的时候玩玩那么些找点乐子。那篇博客解释了我们是何许创设它的,可是在上马在此以前,你能够先本身试试看。

Service Worker 是什么?

1个 service worker
是1段运营在浏览器后台进度里的台本,它独立于方今页面,提供了那多少个不须求与web页面交互的机能在网页背后悄悄施行的力量。在以后,基于它能够落成新闻推送,静默更新以及地理围栏等劳务,不过当前它首先要具备的功用是阻挠和拍卖互联网请求,包蕴可编制程序的响应缓存管理。

为啥说那个API是3个要命棒的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。
  • 瑟维斯worker大批量使用promise,所以要是你不打听怎么是promise,这您供给先读书这篇文章。

生命周期

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

图片 3
上海体育场合是service
worker生命周期,出处

图中得以看来,2个service worker要经历以下进程:

  1.  安装

贰.
 激活,激活成功之后,张开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
部分提供离线体验。就当前来说,我们接纳了 开采者博客 作为大家用来测试的地点。所以一旦你是在大家网址的 开发者博客 部分阅读这篇小说的话,很幸运。

当你使用支持的浏览器访问大家的 开采者博客 中的页面包车型客车时候,1切就准备妥善了。断开你的互联网连接,然后刷新一下页面。假使你协调没规范尝试的话,能够看一下这段 演示摄像(译者注:需梯子)。

Service Worker的生命周期

瑟维斯 worker具备多个截然独立于Web页面包车型的士生命周期。

要让3个service
worker在你的网址上生效,你需求先在您的网页中登记它。注册三个service
worker之后,浏览器会在后台默默运行一个service worker的安装进度。

在设置进度中,浏览器会加载并缓存一些静态财富。假使具备的文件被缓存成功,service
worker就设置成功了。假使有其它公文加载或缓存退步,那么安装进程就会退步,service
worker就不可能被激活(也即没能安装成功)。假使爆发如此的难点,别顾忌,它会在下次再尝试安装。

当安装到位后,service
worker的下一步是激活,在那一阶段,你还足以荣升叁个service
worker的本子,具体内容大家会在背后讲到。

在激活之后,service
worker将接管全数在融洽管辖域范围内的页面,但是1旦2个页面是刚刚注册了service
worker,那么它这一遍不会被接管,到下一回加载页面的时候,service
worker才会生效。

当service
worker接管了页面之后,它可能有二种意况:要么被终止以节约内部存款和储蓄器,要么会处理fetch和message事件,那五个事件分别产生于2个网络请求现身依旧页面上发送了2个音信。

下图是1个简化了的service worker初次安装的生命周期:

图片 5

fetch事件

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

1.
fetch()方法重返的是Promise对象,通过then方法开始展览延续调用,收缩嵌套。ES陆的Promise在成为正式未来,会越来越方便开拓人士。

二. 提供了Request、Response对象,假设做过后端开采,对Request、Response应该比较精通。前端要提倡呼吁能够经过url发起,也得以利用Request对象发起,而且Request能够复用。不过Response用在哪儿啊?在service
worker出现此前,前端确实不会协调给自身发消息,不过有了service
worker,就足以在阻止请求之后依据要求发回本人的响应,对页面来说,这一个普通的请求结果并不曾差异,那是Response的一处选拔。

下边是在中,小编运用fetch
api通过fliker的当众api获取图片的例证,注释中详尽解释了每一步的遵从:

JavaScript

/* 由于是get请求,直接把参数作为query string传递了 */ var URL =
”;
function fetch德姆o() { // fetch(url,
option)援救三个参数,option中能够安装header、body、method信息fetch(U兰德CRUISERL).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
安装事件的1局部,大家得以使用 新的缓存
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(它是 瑟维斯 Worker API 的1有些)以及
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的文章。

打赏帮忙作者翻译越来越多好小说,多谢!

打赏译者

在大家初始写码以前

从这个连串地址拿到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刺探最棒施行。

message事件

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

那是一个双向的进度,页面能够发音讯给service worker,service
worker也能够发送新闻给页面,由于那些特点,可以将service
worker作为中间纽带,使得叁个域名还是子域名下的四个页面能够Infiniti制通讯。

此地是八个小的页面之间通讯demo

打赏援助笔者翻译越来越多好小说,感谢!

图片 6

1 赞 收藏
评论

使用Service Worker

今昔我们有了polyfill,并且消除了HTTPS,让大家看看到底怎么用service
worker。

接纳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是3个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对象未来进行过滤,查看是不是是图片文件,若是还是不是,就径直回到请求,不会缓存。

如若是图表,要先复制1份response,原因是request大概response对象属于stream,只可以采纳1次,之后一份存入缓存,另1份发送给页面。
这便是service worker的强劲之处:拦截请求,伪造响应。fetch
api在此地也起到了一点都不小的功力。

 

service
worker的换代很简单,只要service-worker.js的文件内容有创新,就会采取新的台本。不过有少数要注意:旧缓存文件的铲除、新文件的缓存要在activate事件中举行,因为恐怕旧的页面还在使用在此以前的缓存文件,清除之后会错过作用。

 

在初次使用service worker的经过中,也蒙受了有的主题材料,上边是里面三个

关于小编:Erucy

图片 7

曾经的SharePoint喵星程序猿(一时半刻还挂着微软MVP的名头),今后的Azure/.Net/MongoDB/Cordova/前端程序猿,偶尔写随笔
个人主页 ·
笔者的稿子 ·
46 ·
  

图片 8

怎么注册和装置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是否对你的网站启用了。

图片 9

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

你会发现那个效应能够很有益于地在三个效仿窗口中测试你的service
worker,那样你能够关闭和另行张开它,而不会潜移默化到你的新窗口。任何成立在模仿窗口中的注册服务和缓存在窗口被关门时都将断线鹞子。

主题材料一. 运营时刻

service
worker并不是直接在后台运维的。在页面关闭后,浏览器能够承袭接保险持service
worker运维,也能够关闭service
worker,那有赖于与浏览器本人的作为。所以并非定义1些全局变量,例如上面包车型地铁代码(来自):

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,二,1,一,二….,原因是hitCounter并未平昔留存,若是浏览器关闭了它,下次运转的时候hitCounter就赋值为0了
如此的事情导致调节和测试代码困难,当您更新二个service
worker以往,唯有在开垦新页面未来才可能行使新的service
worker,在调节和测试进程中时常等上一两分钟才会利用新的,相比较抓狂。

Service Worker的设置步骤

在页面上做到登记手续之后,让大家把专注力转到service
worker的本子里来,在那中间,大家要成功它的设置步骤。

在最基本的例证中,你须要为install事件定义2个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就安装成功了。若是其余多个文件下载战败,那么安装步骤就会战败。那几个方法允许你依靠于您本人钦点的富有财富,可是那意味着你须要丰硕谨慎地调整哪些文件供给在设置步骤中被缓存。钦赐了太多的文书的话,就会扩大设置败北率。

地点只是1个简约的例子,你能够在install事件中试行别的操作照旧甚至忽视install事件。

难题二. 权力太大

当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

怎么着缓存和重回Request

你早已安装了service worker,你将来得以回到您缓存的伸手了。

当service
worker被安装成功还要用户浏览了另2个页面大概刷新了脚下的页面,service
worker将上马收受到fetch事件。上边是3个例证:

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里,咱们传入了1个由caches.match发生的promise.caches.match
查找request中被service worker缓存命中的response。

一经我们有3个命中的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只可以被读取二遍,所以大家得将它克隆出来,一份发给浏览器,一份发给缓存。

哪些翻新3个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中奉行3个管理cache的操作。因为您会必要免去掉从前旧的数额。大家在activate而不是install的时候实行那个操作是因为尽管大家在install的时候立时实践它,那么照旧在运转的旧版本的数量就坏了。

此前我们只行使了1个缓存,叫做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);
          }
        })
      );
    })
  );
});

拍卖边界和填坑

那1节内容相比较新,有过多待定细节。希望那1节极快就不要求讲了(因为标准会处理那个难点——译者注),可是未来,这么些故事情节照旧应当被提一下。

比方设置失利了,未有很优雅的法子获取通报

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

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

fetch()近年来仅扶助Service Workers

fetch即刻协助在页面上接纳了,可是当前的Chrome完毕,它还只辅助service
worker。cache
API也即就要页面上被辅助,不过最近结束,cache也还不得不在service
worker中用。

fetch()的默许参数

当你选拔fetch,缺省级地区级,请求不会带上cookies等凭证,要想带上的话,供给:

JavaScript

fetch(url, { credentials: ‘include’ })

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

这么设计是有理由的,它比XHLAND的在同源下暗中认可发送凭据,但跨域时屏弃凭据的规则要来得好。fetch的表现更像其余的COCR-VS请求,例如<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

Non-CO奇骏S暗中同意不补助

暗许情状下,从第壹方UTiggoL跨域获得叁个财富将会倒闭,除非对方援助了COHummerH贰S。你能够加上三个non-COLX570S选项到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.’);
});

fetch()不根据30x重定向规范

不幸,重定向在fetch()中不会被触发,这是日前版本的bug;

处理响应式图片

img的srcset属性或然<picture>标签会根据情况从浏览器或者网络上选择最合适尺寸的图片。

在service worker中,你想要在install步骤缓存二个图纸,你有以下几种选用:

  1. 安装具备的<picture>元素或者将被请求的srcset属性。
  2. 安装单1的low-res版本图片
  3. 安装单一的high-res版本图片

正如好的方案是2或叁,因为假如把装有的图片都给下载下来存着有点浪费内部存款和储蓄器。

万一你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互连网上下载high-res的本子,可是只要high-res版本下载退步以来,就照旧用low-res版本。这些想法很好也值得去做,可是有3个标题:

假诺大家有上面三种图片:

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" />

借使咱们在1个二x的显得形式下,浏览器会下载image-二x.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;" />

图片 11

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

改变URL Hash的Bug

在M40版本中存在1个bug,它会让页面在退换hash的时候产生service
worker截止工作。

你能够在那里找到愈来愈多相关的消息: 

更多内容

此处有一些生死相依的文书档案能够参见:

获得赞助

1经您遇见麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家立马跟进和尽恐怕援救你消除问题。

赞 2 收藏
评论

图片 8

相关文章

Post Author: admin

发表评论

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