目前,service worker已经作为草案被提出,可以实现消息推动、地理围栏、离线应用等功能,相当于在浏览器端建立了一个代理服务,实现一些现在看来逆天的功能。
目前原生App跟HTML5相比具有如下优势:富离线体验、消息推送、定时默认更行等功能,这些优势决定了HTML5无法取代native。service worker(后面简称sw)就是在这样的背景下提出来的。
sw是一段运行在浏览器后端的脚本,独立于页面,是一个worker,也可以理解为一个网络代理服务器。因此sw是无法与DOM进行交互的,但是可以与js主线程进行通信。
目前sw还是一个草案,各个浏览器支持程度还不是很高,除了chrome 40、firefox以外,其他浏览器均不支持该功能,但是sw提供的逆天功能还是非常值得期待:
其中最期待的还是通过HTTP请求的拦截,进而实现离线应用,提升页面的性能体验。
a.首先在页面注册一个service worker
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('./index.js').then((reg) => { console.log('register a service worker: ', reg) }).catch((err) => { console.log('err: ', err); }); }
b.接着就可以在Service worker中尽情畅想
以页面的离线应用为出发点,说明sw如实做到离线应用的。
const cacheUrl = [ '/base.css', '/france.html' ]; const cacheName = 'my-site-cache'; // install阶段 self.addEventListener('install', (event) => { console.log('sw event: install'); event.waitUntil( caches.open(cacheName).then((cache) => { console.log('open cache'); return cache.addAll(cacheUrl); }) ); }); self.addEventListener('fetch', (event) => { event.respondWith(caches.match(event.request).then(res => { if (res) { console.log('match'); return res; } return fetch(event.request); })); });
sw的说明周期主要包括三个阶段: install、active、working。下面这张图说明各个阶段完成的工作:
sw本质上也是一个worker,所以sw开发也是建立在事件的基础上,通过事件机制完成相关业务逻辑的处理。
其中sw里面的事件在原始事件对象 EVENT ,进行了拓展,例如fetch event里面拥有respondWith、waitUtil方法。
cache api就是对http的request/response进行缓存管理,是在service worker的规范中定义的,往往跟service worker一起操作使用,是实现web app离线应用的关键一环。但是cache api又不依赖于service worker,可以单独在window下使用,。
在window对象下,cache api的操作封装在 caches
对象下面,里面的操作分为两类: 对cache的操作、对cache里面http的操作。下面简单说明下cache storage的相关操作:
// 下面是对cache的相关操作 // open: 创建或打开一个cache caches.open('test').then(cache => { return cache.add('/base.css') }).then((val) => { console.log('create a cache and add "base.css" to it'); }); // 在cache storage查找缓存的资源 caches.match('/base.css').then(res => { if (!res) return 'can not find this http in caches storage'; return res.text() }).then((result) => { console.log(result) }); // 得到所有的cache caches.keys().then(name => { console.log('names: ', name) }); // 得到某个cache caches.delete('test').then(val => { console.log('delete success?: ', val) }); // 对cache里面http进行操作 caches.open('test').then(cache => { // 添加缓存资源 return cache.add('/base.css') }).then((val) => { console.log('create a cache and add "base.css" to it'); }); caches.open('test').then(cache => { // 资源匹配 return cache.match('/base.css') }).then(res => { return res.text() }).then(str => { console.log(str) });