菜单

瑟维斯 Worker初体验

2019年4月14日 - XML

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

最初的小说出处: AlloyTeam   

在201四年,W3C宣布了service worker的草案,service
worker提供了许多新的能力,使得web app拥有与native
app相同的离线体验、音信推送体验。
service worker是1段脚本,与web
worker壹样,也是在后台运营。作为1个独自的线程,运营环境与一般脚本不相同,所以无法直接参加web交互行为。native
app能够形成离线使用、音讯推送、后台自动更新,service
worker的面世是多亏为了使得web app也能够有所类似的能力。

 

service worker可以:

  1. 后台新闻传递
  2. 互连网代理,转发呼吁,伪造响应
  3. 离线缓存
  4. 音讯推送
  5.  … …

正文以财富缓存为例,说雀巢(Beingmate)下service worker是何等工作的。

作用:

能够使你的使用先拜访当地缓存财富,所以在离线状态时,在未曾经过互联网收到到越来越多的数额前,还是能够提供基本的功效。

生命周期

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

图片 1
上海体育地方是service
worker生命周期,出处http://www.html5rocks.com/en/tutorials/service-worker/introduction/

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

  1.  安装

二.
 激活,激活成功之后,打开chrome://inspect/#service-workers能够查看到日前运作的service
worker

图片 2

  1. 监听fetch和message事件,上面三种事件会实行不难描述

  2. 销毁,是或不是销毁由浏览器决定,要是二个service
    worker长时间不行使恐怕机器内部存款和储蓄器有数,则或者会销毁那几个worker

运用前的设置:

Chrome中需求敞开相关配置: 访问
chrome://flags 并打开
experimental-web-platform-features; 重启浏览器
(注意:某个天性在Chrome中从未暗中同意开放扶助);其余,你需求经过 HTTPS
来访问你的页面 — 出于安全原因,Service Workers 供给要在必得在 HTTPS
下才能运作,localhost 也被浏览器认为是安全源。

fetch事件

在页面发起http请求时,service
worker能够通过fetch事件拦截请求,并且付诸本人的响应。
w三c提供了贰个新的fetch
api,用于代替XMLHttpRequest,与XMLHttpRequest最大分裂有两点:

一.
fetch()方法再次来到的是Promise对象,通过then方法开始展览连续调用,收缩嵌套。ES陆的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(U昂CoraL).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帮助。

容易的事例

那是把express和sw-test简单结合的多少个小demo, 项目运维起来访问
http://localhost:3000/sw-test/index.html
,
然后停止此服务仍是能够访问相应财富。Github

message事件

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

那是一个双向的进度,页面能够发音信给service worker,service
worker也足以发送新闻给页面,由于那一个特点,能够将service
worker作为中间纽带,使得三个域名依旧子域名下的八个页面能够随意通讯。

此地是一个小的页面之间通讯demohttps://nzv3tos3n.qnssl.com/message/msg-demo.html

连带代码

  1. 首先判断了浏览器是还是不是匡助
  2. 调用 register 方法注册 service worker, 第二个参数是运维 service
    worker 的
    js 文件, 第三个 scope 参数是选填的,能够被用来钦命你想让 service
    worker 控制的剧情的子目录。 在那一个例子,我们钦定了 ‘/sw-test/’,即
    http://localhost:3000/sw-test/
    下的呼吁会被抓走, 被钦定的财富会被缓存。
  3. 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);
  });
}
  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()
    创造了二个响应对象的克隆,这些目的在具有方面都以同等的,不过存款和储蓄在一个不等的变量中。制止反复施用篡改了对象。

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

先是定义了急需缓存的文件数组cacheFile,然后在install事件中,缓存这个文件。
evt是2个Install伊夫nt对象,继承自Extendable伊芙nt,当中的waitUntil()方法接收叁个promise对象,直到这个promise对象成功resolve之后,才会持续运行service-worker.js。
caches是3个CacheStorage对象,使用open()方法打开三个缓存,缓存通过名称进行区分。
取得cache实例之后,调用addAll()方法缓存文件。

诸如此类就将文件添加到caches缓存中了,想让浏览器选取缓存,还亟需拦截fetch事件

JavaScript

// 缓存图片 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; }); }) ) });

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起到了1个当中代理的意义。

service worker请求的长河通过fetch
api完毕,得到response对象以往举行过滤,查看是不是是图片文件,若是或不是,就平素回到请求,不会缓存。

倘假如图片,要先复制一份response,原因是request只怕response对象属于stream,只好选拔贰次,之后一份存入缓存,另壹份发送给页面。
那便是service worker的无敌之处:拦截请求,伪造响应。fetch
api在此间也起到了不小的成效。

 

service
worker的更新相当粗略,只要service-worker.js的文书内容有更新,就会使用新的脚本。不过有一些要留意:旧缓存文件的破除、新文件的缓存要在activate事件中展开,因为可能旧的页面还在应用在此之前的缓存文件,清除之后会失掉意义。

 

在第二使用service worker的长河中,也赶上了部分标题,下边是其中四个

本子更新删除旧缓存

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

题材一. 运维时刻

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

再次来到的结果恐怕是尚未规律的:一,二,壹,2,1,一,二….,原因是hitCounter并未向来留存,若是浏览器关闭了它,下次运维的时候hitCounter就赋值为0了
如此那般的事务导致调节和测试代码困难,当你更新一个service
worker未来,唯有在打开新页面未来才可能使用新的service
worker,在调节进程中平日等上壹两分钟才会动用新的,相比抓狂。

参照 MDN

Service Worker
详细文书档案

题材二. 权力太大

当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 收藏
评论

图片 3

相关文章

发表评论

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

网站地图xml地图