菜单

Service Worker初体验

2019年4月8日 - JavaScript

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

初稿出处: AlloyTeam   

在201四年,W3C发布了service worker的草案,service
worker提供了重重新的能力,使得web app拥有与native
app相同的离线体验、信息推送体验。
service worker是一段脚本,与web
worker1样,也是在后台运维。作为3个独立的线程,运转环境与平日脚本分裂,所以不可能直接插足web交互行为。native
app能够形成离线使用、新闻推送、后台自动更新,service
worker的产出是多亏为了使得web app也足以具有类似的能力。

 

service worker可以:

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

本文以财富缓存为例,说可瑞康下service worker是如何是好事的。

作用:

能够使您的选择先走访本地缓存能源,所以在离线状态时,在尚未经过互联网收到到更加多的多少前,还是能够提供基本的作用。

生命周期

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

图片 1
上航海用教室是service
worker生命周期,出处http://www.html5rocks.com/en/tutorials/service-worker/introduction/

图中得以见见,3个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在改为规范未来,会进一步便利开发人士。

2. 提供了Request、Response对象,要是做过后端开发,对Request、Response应该相比较熟识。前端要提倡呼吁能够因而url发起,也能够选取Request对象发起,而且Request能够复用。然而Response用在哪儿呢?在service
worker出现在此以前,前端确实不会友善给协调发音信,不过有了service
worker,就足以在阻碍请求之后传说要求发回本人的响应,对页面而言,那几个普通的乞求结果并未不一样,那是Response的1处选取。

下边是在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奥迪Q三L).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帮衬。

简易的例证

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

message事件

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

那是二个双向的历程,页面能够发音信给service worker,service
worker也得以发送音信给页面,由于这几个特点,能够将service
worker作为中间纽带,使得一个域名还是子域名下的三个页面能够四意通讯。

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

连带代码

  1. 首先判断了浏览器是否援助
  2. 调用 register 方法注册 service worker, 第二个参数是运作 service
    worker 的
    js 文件, 第3个 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 1样, 是揭露在 window
    效用域下的。固然它被定义在 service worker 的标准中,
    可是它不必一定要同盟 service worker
    使用.Cache详细API
  3. event.respondWith
    方法意在包裹代码,那么些代码为来源受控页面包车型地铁request生成自定义的response,翻开更加多。response.clone()
    创造了贰个响应对象的仿造,那几个指标在富有地方都以平等的,可是存款和储蓄在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');
      });
    }
  }));
});

选用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是一个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起到了三个中间代理的功用。

service worker请求的长河通过fetch
api达成,获得response对象现在进行过滤,查看是不是是图片文件,假诺不是,就径直再次回到请求,不会缓存。

一旦是图表,要先复制1份response,原因是request或然response对象属于stream,只好选用贰遍,之后壹份存入缓存,另一份发送给页面。
那就是service worker的精锐之处:拦截请求,伪造响应。fetch
api在此间也起到了极大的作用。

 

service
worker的换代很简短,只要service-worker.js的文件内容有创新,就会使用新的台本。可是有一些要留意:旧缓存文件的解决、新文件的缓存要在activate事件中开始展览,因为或然旧的页面还在运用以前的缓存文件,清除之后会失去意义。

 

在首先使用service worker的历程中,也遇上了壹些难点,上面是里面五个

本子更新删除旧缓存

  1. 监听 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);
        }
      }));
    })
  );
});

标题1. 运作时刻

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,二….,原因是hitCounter并不曾直接存在,如若浏览器关闭了它,下次运转的时候hitCounter就赋值为0了
这么的事情导致调节和测试代码困难,当你更新一个service
worker今后,唯有在开辟新页面以往才只怕选拔新的service
worker,在调节过程中时常等上一两分钟才会利用新的,比较抓狂。

参照 MDN

Service Worker
详细文书档案

题材2. 权力太大

当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地图