Service Worker初体验
2016/01/06 · JavaScript
· Service Worker
原稿出处: AlloyTeam
在2014年,W3C公布了service worker的草案,service
worker提供了不少新的能力,使得web app拥有与native
app相同的离线体验、音讯推送体验。
service worker是1段脚本,与web
worker一样,也是在后台运维。作为3个单身的线程,运营环境与经常脚本不一致,所以无法直接插足web交互行为。native
app能够形成离线使用、新闻推送、后台自动更新,service
worker的产出是多亏为了使得web app也足以享有类似的能力。
service worker可以:
- 后台音讯传递
- 互连网代理,转载呼吁,伪造响应
- 离线缓存
- 新闻推送
- … …
正文以财富缓存为例,说爱他美下service worker是哪些做事的。
本子更新删除旧缓存
- 监听 activate 事件, 如当前版本 v二,删除与当下不相配缓存数据。
this.addEventListener('activate', function(event) {
var cacheWhitelist = ['v2'];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
message事件
页面和serviceWorker之间能够透过posetMessage()方法发送信息,发送的消息能够通过message事件接收到。
那是五个双向的进程,页面能够发新闻给service worker,service
worker也得以发送消息给页面,由于这么些特点,可以将service
worker作为中间纽带,使得二个域名依旧子域名下的八个页面能够私自通讯。
此地是一个小的页面之间通讯demohttps://nzv3tos3n.qnssl.com/message/msg-demo.html
参照 MDN
标题二. 权力太大
当service worker监听fetch事件过后,对应的央浼都会由此service
worker。通过chrome的network工具,能够看看此类请求会标明:from service
worker。若是service
worker中冒出了难题,会促成全体请求退步,包含普通的html文件。所以service
worker的代码品质、容错性一定要很好才能担保web app符合规律运作。
参考文章:
1. http://www.html5rocks.com/en/tutorials/service-worker/introduction/
2. http://www.sitepoint.com/introduction-to-the-fetch-api/
3. https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent
4. https://developer.mozilla.org/en-US/docs/Web/API/ExtendableEvent
5. https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage
1 赞 3 收藏
评论
相关代码
- /public/sw-test/app.js
- 第3判断了浏览器是不是扶助
- 调用 register 方法注册 service worker, 第3个参数是运作 service
worker 的
js 文件, 第四个 scope 参数是选填的,能够被用来钦命你想让 service
worker 控制的情节的子目录。 在这些例子,我们钦点了 ‘/sw-test/’,即
http://localhost:3000/sw-test/
下的伸手会被擒获, 被内定的能源会被缓存。 - register 方法重临七个 Promise , 举办不易错误处理。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' }).then(function(reg) {
// registration worked
console.log('Registration succeeded. Scope is ' + reg.scope);
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
}
- /public/sw-test/sw.js
基本文件,监听安装事件, 打开缓存 v1 扩大内需缓存财富 request url
list, 截取被控文件下请求, 假若不设有该缓存则展开缓存处理
- 监听了 install 事件, event.waitUntil 重要用在 Install, activate
事件中,
在服务工作线程中,延长事件的寿命从而阻碍浏览器在事变中的异步操作实现以前终止劳动工作线程。 - Cache 接口提供缓存的
Request,
Response
对象对的蕴藏机制,例如作为ServiceWorker
生命周期的一局地。
Cache 接口像 workers 1样, 是揭穿在 window
功效域下的。固然它被定义在 service worker 的正规中,
可是它不必一定要合作 service worker
使用.Cache详细API - event.respondWith
方法目的在于包裹代码,那个代码为来自受控页面包车型客车request生成自定义的response,翻看更多。response.clone()
创造了一个响应对象的仿造,那些目的在有着方面都以1律的,可是存款和储蓄在叁个不及的变量中。防止反复用到篡改了对象。
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v1').then(function(cache) {
return cache.addAll([
'/sw-test/',
'/sw-test/index.html',
'/sw-test/style.css',
'/sw-test/app.js',
'/sw-test/image-list.js',
'/sw-test/star-wars-logo.jpg',
'/sw-test/gallery/bountyHunters.jpg',
'/sw-test/gallery/myLittleVader.jpg',
'/sw-test/gallery/snowTroopers.jpg'
]);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(caches.match(event.request).then(function(response) {
// caches.match() always resolves
// but in case of success response will have value
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then(function (response) {
// response may be used only once
// we need to save clone to put one copy in cache
// and serve second one
let responseClone = response.clone();
caches.open('v1').then(function (cache) {
cache.put(event.request, responseClone);
});
return response;
}).catch(function () {
return caches.match('/sw-test/gallery/myLittleVader.jpg');
});
}
}));
});
使用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是3个特例。
挂号结束,以往初步写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);
})
);
});
|
第2定义了亟待缓存的公文数组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能够回到本身的响应。
第二检缓存中是或不是早已缓存了这些请求,假设有,就一直重临响应,就裁减了3次互连网请求。不然由service
workder发起请求,那时的service workder起到了1当中间代理的效率。
service worker请求的长河通过fetch
api完毕,得到response对象以往举办过滤,查看是还是不是是图片文件,假诺不是,就径直再次来到请求,不会缓存。
比方是图表,要先复制壹份response,原因是request可能response对象属于stream,只好利用贰回,之后1份存入缓存,另一份发送给页面。
那正是service worker的强劲之处:拦截请求,伪造响应。fetch
api在此地也起到了十分大的效应。
service
worker的更新非常粗大略,只要service-worker.js的文书内容有立异,就会动用新的脚本。但是有几许要专注:旧缓存文件的排除、新文件的缓存要在activate事件中进行,因为可能旧的页面还在运用以前的缓存文件,清除之后会失掉功用。
在初次使用service worker的进程中,也蒙受了有的题材,下边是里面三个
归纳的例证
那是把express和sw-test不难结合的三个小demo, 项目周转起来访问
http://localhost:3000/sw-test/index.html
,
然后停下此服务还能访问相应财富。Github
标题一. 运维时刻
service
worker并不是直接在后台运转的。在页面关闭后,浏览器能够一而再保持service
worker运行,也得以关闭service
worker,那有赖于与浏览器本身的一颦一笑。所以不要定义一些全局变量,例如上面包车型地铁代码(来自https://jakearchibald.com/2014/service-worker-first-draft/):
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,2,壹,一,二….,原因是hitCounter并未直接存在,假诺浏览器关闭了它,下次起动的时候hitCounter就赋值为0了
那般的作业导致调节和测试代码困难,当你更新3个service
worker现在,唯有在开拓新页面未来才大概应用新的service
worker,在调节进度中不时等上壹两分钟才会使用新的,相比抓狂。
作用:
可以使您的采用先拜访本地缓存财富,所以在离线状态时,在未有经过网络收到到更加多的多少前,还能够提供基本的功用。
生命周期
先来看一下三个service worker的运作周期
上航海用体育场面是service
worker生命周期,出处http://www.html5rocks.com/en/tutorials/service-worker/introduction/
图中能够见见,一个service worker要经历以下进程:
- 安装
②.
激活,激活成功之后,打开chrome://inspect/#service-workers能够查阅到目前运维的service
worker
-
监听fetch和message事件,上边三种事件会议及展览开简要描述
-
销毁,是不是销毁由浏览器决定,假若三个service
worker长时间不应用照旧机器内部存款和储蓄器有数,则大概会销毁这一个worker
利用前的装置:
Chrome中需求打开相关安排: 访问
chrome://flags 并拉开
experimental-web-platform-features; 重启浏览器
(注意:某个天性在Chrome中从不暗中同意开放扶助);别的,你须要通过 HTTPS
来访问你的页面 — 出于安全原因,Service Workers 供给要在必须在 HTTPS
下才能运作,localhost 也被浏览器认为是安全源。
fetch事件
在页面发起http请求时,service
worker能够经过fetch事件拦截请求,并且付诸本人的响应。
w三c提供了3个新的fetch
api,用于代替XMLHttpRequest,与XMLHttpRequest最大分裂有两点:
一.
fetch()方法再次来到的是Promise对象,通过then方法进行连接调用,减弱嵌套。ES6的Promise在改为规范之后,会特别便利开发人士。
贰. 提供了Request、Response对象,假诺做过后端开发,对Request、Response应该相比较熟识。前端要发起呼吁能够通过url发起,也能够行使Request对象发起,而且Request可以复用。可是Response用在何地吧?在service
worker现身在此以前,前端确实不会自个儿给本人发新闻,不过有了service
worker,就能够在阻拦请求之后据他们说供给发回自身的响应,对页面而言,那些平凡的乞请结果并从未分别,那是Response的壹处采用。
上边是在http://www.sitepoint.com/introduction-to-the-fetch-api/中,笔者采用fetch
api通过fliker的公然api获取图片的事例,注释中详细分解了每一步的作用:
JavaScript
/* 由于是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 fetch德姆o() { // fetch(url,
option)协理七个参数,option中能够设置header、body、method消息fetch(UOdysseyL).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
4二初步扶助,对于旧浏览器,可以由此官方维护的polyfill协助。