菜单

Service Worker

2019年4月22日 - Html/Html5

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

原来的文章出处: AlloyTeam   

在201肆年,W3C揭橥了service worker的草案,service
worker提供了过多新的才具,使得web app具备与native
app一样的离线体验、音信推送体验。
service worker是1段脚本,与web
worker同样,也是在后台运营。作为一个独门的线程,运维景况与普通脚本不相同,所以不能够直接参与web交互行为。native
app可以完结离线使用、音讯推送、后台自动更新,service
worker的面世是多亏为了使得web app也可以具有类似的手艺。

 

service worker可以:

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

本文以能源缓存为例,说喜宝(Hipp)下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. 销毁,是或不是销毁由浏览器决定,即使3个service
    worker长期不应用依旧机器内部存款和储蓄器有数,则恐怕会销毁这几个worker

使用前的装置:

Chrome中必要展开相关计划: 访问
chrome://flags 并开启
experimental-web-platform-features; 重启浏览器
(注意:有些个性在Chrome中从不暗中同意开放扶助);此外,你须要经过 HTTPS
来访问你的页面 — 出于安全原因,Service Workers 供给要在必得在 HTTPS
下技能运作,localhost 也被浏览器认为是安全源。

fetch事件

在页面发起http请求时,service
worker能够通过fetch事件拦截请求,并且付诸本人的响应。
w3c提供了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(U翼虎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
4二起头支持,对于旧浏览器,能够通过官方维护的polyfill支持。

大致的例证

那是把express和sw-test简单结合的一个小demo, 项目周转起来访问
http://localhost:3000/sw-test/index.html
,
然后停下此服务还能够访问相应能源。Github

message事件

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

那是1个双向的进度,页面能够发音信给service worker,service
worker也足以发送信息给页面,由于这一个天性,能够将service
worker作为中间纽带,使得1个域名依然子域名下的三个页面能够轻巧通讯。

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

连带代码

  1. 首先判别了浏览器是不是匡助
  2. 调用 register 方法注册 service worker, 第3个参数是运作 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生命周期的1有个别。
    Cache 接口像 workers 同样, 是揭破在 window
    效率域下的。就算它被定义在 service worker 的正经中,
    然则它不用一定要协作 service worker
    使用.Cache详细API
  3. event.respondWith
    方法目的在于包裹代码,这一个代码为来自受控页面包车型地铁request生成自定义的response,查看更加多。response.clone()
    创制了3个响应对象的仿制,那些目的在颇具方面都是同一的,不过存款和储蓄在3个两样的变量中。幸免反复应用篡改了对象。

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缓存文件

上面介绍3个运用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是3个Install伊夫nt对象,承袭自Extendable伊芙nt,在那之中的waitUntil()方法接收一个promise对象,直到这几个promise对象成功resolve之后,才会持续运营service-worker.js。
caches是3个CacheStorage对象,使用open()方法展开3个缓存,缓存通过名称进行区分。
获取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对象今后举办过滤,查看是不是是图片文件,如若不是,就径直回到请求,不会缓存。

倘假如图表,要先复制1份response,原因是request可能response对象属于stream,只可以动用一次,之后壹份存入缓存,另壹份发送给页面。
那就是service worker的强劲之处:拦截请求,伪造响应。fetch
api在此处也起到了十分大的遵循。

 

service
worker的翻新一点也不细略,只要service-worker.js的文本内容有更新,就会使用新的本子。可是有一些要留意:旧缓存文件的铲除、新文件的缓存要在activate事件中展开,因为可能旧的页面还在应用以前的缓存文件,清除之后会失掉意义。

 

在初次使用service worker的历程中,也遇上了1部分题材,上面是内部多少个

本子更新删除旧缓存

  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了
那般的事务导致调节和测试代码困难,当你更新3个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地图