Service Worker初体验

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

原稿出处: AlloyTeam   

在二零一六年,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.  … …

正文以能源缓存为例,说可瑞康(Karicare)下service worker是何许做事的。

简书放不了demo,demo能够看原文

作用:

能够使您的应用先访问当地缓存能源,所以在离线状态时,在尚未经过互联网收到到越多的数额前,仍可以够提供基本的效益。

Service Worker是什么


从效率上来说,Service Worker是一种提供离线缓存控制作用的一种Worker,同时,也存有音讯推送和后台同步的效用,能够透过ServiceWorker来缓存网页的能源,然后拦截Fetch请求来实施相应的缓存处理操作。因为是一种Worker,所以ServiceWorker也拥有Worker的部分着力特点,例如:

  • 独自于主线程运维
  • 不能访问window目的,不过富有自身的2个履行上下文,例如Service WorkerServiceWorkerGlobalScope
  • 具有信息api来和页面举办新闻交互

ServiceWorker是一种共享型Worker,它差异于专用型Worker只可以在创设它的页面中选取,暗中认可配置下,service
Worker能够被日前登记脚本的域名下拥有页面公用。
也便是说,只要在3个根域名注册三个ServiceWorker,那么全数这么些域名下的页面都会收下影响。

生命周期

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

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

图中能够看来,三个service worker要经历以下进程:

  1.  安装

2.
 激活,激活成功之后,打开chrome://inspect/#service-workers能够查看到当下运转的service
worker

图片 2

  1. 监听fetch和message事件,下边二种事件会开始展览简易描述

  2. 销毁,是或不是销毁由浏览器决定,假诺1个service
    worker长时间不使用大概机器内部存款和储蓄器有数,则可能会销毁这一个worker

Service Worker 是什么?

service worker 是独立于近日页面包车型客车一段运营在浏览器后台进度里的脚本。
service worker不供给用户打开 web
页面,也不要求别的交互,异步地运转在一个完全部独用立的上下文环境,不会对主线程造成堵塞。基于service
worker能够兑现消息推送,静默更新以及地理围栏等劳动。
service
worker提供一种渐进增强的特色,使用天性检查和测试来慢慢增强,不会在老旧的不支持service workers 的浏览器中生出震慑。能够由此service
workers化解让应用程序能够离线工作,让存款和储蓄数据在离线时利用的标题。

注意事项:
1.service
worker运作在它们自身的一点一滴独创新步的大局上下文中,也正是说它们有谈得来的器皿。
Service Worker初体验。2.service
worker尚未一贯操作DOM的权杖,但是能够通过postMessage方法来与Web页面通讯,让页面操作DOM。
3.service
worker是3个可编制程序的网络代理,允许开发者控制页面上拍卖的网络请求。
4.浏览器大概天天回收service
worker,在不被利用的时候,它会融洽终止,而当它再也被用到的时候,会被重复激活。
5.service worker的生命周期是由事件驱动的而不是经过Client。

接纳前的安装:

Chrome中须求开启相关布署: 访问
chrome://flags 并拉开
experimental-web-platform-features; 重启浏览器
(注意:有个别天性在Chrome中绝非私下认可开放帮助);别的,你需求通过 HTTPS
来访问你的页面 — 出于安全原因,Service Workers 须求要在必须在 HTTPS
下才能运转,localhost 也被浏览器认为是安全源。

Service Worker使用


要使用ServiceWorker,首先,必要通过serviceWorkerContainer.register()来举办挂号,例如:

ServiceWorkerContainer.register("/test/service.js", {scope:"./"})
    .then(
        function(ServiceWorkerRegistration) {
            // do something
        }
);

一经当前域名为www.baidu.com/serviceWork,那么地点的措施就在www.baidu.com/serviceWork/test上面注册了三个ServiceWorker,要是把scope改成./hahaha,那么功效域就改为了www.baidu.com/serviceWork/test/hahaha,只要处于这么些域名之下的持有页面,都遭到那么些ServiceWorker的主宰。不过,假若将scope改成”../”,页面就会报出贰个荒谬,因为那时候不容许设置比service.js所在地点层级更高的门路,除非添加3个Service-Worker-Allowedheader。

注册成功今后,受控界面会去安装serviceWorker,安装到位之后会处于等候处境,接下去有恐怕会跻身激活状态,激活状态之后,页面还不自然是受控的,不过有对应的api可以操纵这一多重流程。这个流程正是ServiceWorker最最复杂的生命周期了。

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 fetch德姆o() { // fetch(url,
option)援救七个参数,option中得以设置header、body、method信息fetch(U福特ExplorerL).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帮忙。

Service Worker生命周期

service worker拥有三个通通独立于Web页面包车型地铁生命周期

图片 3

sw-lifecycle.png

  1. 注册service worker,在网页上生效
  2. 安装成功,激活 也许 安装失利(下次加载会尝试重新安装)
  3. 激活后,在sw的作用域下成效具有的页面,首次决定sw不会生效,下次加载页面才会生效。
  4. sw作用页面后,处理fetch(互联网请求)和message(页面消息)事件 恐怕被甘休(节省里存)。

不难的例子

那是把express和sw-test不难结合的二个小demo, 项目运作起来访问
http://localhost:3000/sw-test/index.html
,
然后截止此服务还是能够访问相应能源。Github

ServiceWorker生命周期


serviceWorker的生命周期有点复杂,情形多多,然而基本上符合一个观点,那正是渐进式。

message事件

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

那是2个双向的经过,页面能够发消息给service worker,service
worker也能够发送音讯给页面,由于那一个特点,可以将service
worker作为中间纽带,使得贰个域名依然子域名下的五个页面可以自由通讯。

此处是3个小的页面之间通讯demo

Service Worker支持使用

有关代码

  • /public/sw-test/app.js
  1. 先是判断了浏览器是或不是支持
  2. 调用 register 方法注册 service worker, 第贰个参数是运维 service
    worker 的
    js 文件, 首个 scope 参数是选填的,能够被用来内定你想让 service
    worker 控制的始末的子目录。 在那个事例,我们内定了 ‘/sw-test/’,即
    http://localhost:3000/sw-test/
    下的央求会被抓获, 被钦点的能源会被缓存。
  3. register 方法返回1个 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, 截取被控文件下请求, 假使不设有该缓存则开始展览缓存处理
  1. 监听了 install 事件, event.waitUntil 主要用在 Install, activate
    事件中,
    在劳动办事线程中,延长事件的寿命从而阻碍浏览器在事件中的异步操作完毕此前终止服务办事线程。
  2. Cache 接口提供缓存的
    Request,
    Response
    对象对的仓库储存机制,例如作为ServiceWorker生命周期的一局部。
    Cache 接口像 workers 一样, 是暴光在 window
    功能域下的。即便它被定义在 service worker 的正儿八经中,
    可是它不用一定要同盟 service worker
    使用.Cache详细API
  3. event.respondWith
    方法目的在于包裹代码,这个代码为来源受控页面包车型客车request生成自定义的response,翻开愈多。response.clone()
    创造了1个响应对象的仿造,那么些指标在全部地点都是平等的,可是存款和储蓄在2个两样的变量中。幸免频仍接纳篡改了目的。

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');
      });
    }
  }));
});

install

实施完登记之后,浏览器会去下载,倘使脚本没有错误的话,就会开始展览安装,安装会在Worker内触发install事件,安装分为八个情形:installinginstalled,那里能够执行一些操作。

self.addEventListener("install",installEvent=>{
    self.skipWaiting();//跳过waiting
    installEvent.waitUntil(
        caches.open(CACHE_NAME).then(cache=>{
            return cache.add("http://upload.jianshu.io/users/upload_avatars/9545112/f186bd4a-1da4-4912-b926-a744bc128d06.png?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240");
        })
    )

});

那里会有三个install伊夫nt,通过waitUtil格局能够隔开分离安装状态,那几个主意能够流传三个promise,唯有那些promise正确resolve之后,才会达成安装,同时,还有1个skipwaiting方法,这些格局能够跳过installed和activating状态之间的waiting状态。
第3回打开页面会安装work,然后接下去再检查和测试到新的work也会重复实施安装。
接触更新的三种情况:

  • 率先次导航到功能域范围内页面包车型大巴时候
  • 当在24小时内并未进展立异检测并且触发效用性时间如push或sync的时候
  • SW 的 UPAJEROL 发生变化并调用.register()时
  • 手动执行reg.update()
  • 重载页面(有个别景况下不会更新,原因不明)

立异会比对旧版本和新本子的字节,固然字节不雷同,则更新。在创新install达成未来,会进去waiting状态,直到旧版本不控制任何client(受控的页面)再进来activating状态。

动用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代码。
基于前边的生命周期图,在3个新的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()方法打开2个缓存,缓存通过名称进行区分。
赢得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的长河中,也碰着了一些题材,上面是里面四个

浏览器扶助

service worker
support

图片 4

navigator-serviceworker.png

本子更新删除旧缓存

  1. 监听 activate 事件, 如当前版本 v2,删除与如今不匹配缓存数据。

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);
        }
      }));
    })
  );
});

activate

activate的意况比测试妹子的盘算逻辑还难推测。不过那么些依照一个尺码,唯有具备的页面都不受老的serviceWorker控制的时候,才会伊始激活。意思正是独具worker功能的页面都关了,也正是重启更新,再度运行的时候,才会进去激活状态。激活也会接触2个activate状态.

self.addEventListener("activate", ExtendableEvent => {
  ExtendableEvent.waitUntil(self.clients.claim());
 }

activate也和install一样,也有waitUtil办法,效果也是一模一样的。激活成功今后实际还不必然有效益,因为页面大概还处于不受控的动静,大概有其它叁个页面,没有刷新的,不过这么些时候新开二个页面更新了work,那个时候就需求调用clients.claim操作来让全数打开的页面受控。可是…work的进行是异步的,相当于说,页面在履行这一个点子以前是不受控,可能是否受最新的work控制的,在运用work来缓存的时候,就会并发难点,导致版本不相同等,所以,个人感觉serviceWorker比较适合做3个支持者,没有也行,有也行,能够因而设置二个button之类的来唤醒用户,发现新本子,是还是不是要求刷新之类的操作。
上面那张图很好的席卷了生命周期

图片 5

生命周期

发表评论

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

网站地图xml地图