菜单

Service Worker

2019年4月18日 - JavaScript

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

初稿出处: AlloyTeam   

在201四年,W3C公布了service worker的草案,service
worker提供了无数新的技能,使得web app具有与native
app一样的离线体验、音讯推送体验。
service worker是一段脚本,与web
worker同样,也是在后台运转。作为1个独立的线程,运转条件与平日脚本不一样,所以无法直接参与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/

图中得以见到,一个service worker要经历以下进度:

  1.  安装

2.
 激活,激活成功未来,张开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最大差别有两点:

1.
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(UTiggoL).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, 第2个参数是运营 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()
    创造了二个响应对象的克隆,那一个指标在具备方面都以一样的,不过存款和储蓄在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缓存文件

下边介绍三个选择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代码。
依照后面包车型地铁生命周期图,在2个新的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对象以后实行过滤,查看是还是不是是图片文件,如若不是,就径直重临请求,不会缓存。

比方是图形,要先复制①份response,原因是request恐怕response对象属于stream,只可以采纳2遍,之后1份存入缓存,另一份发送给页面。
那正是service worker的庞大之处:拦截请求,伪造响应。fetch
api在此间也起到了十分的大的效果。

 

service
worker的创新很简短,只要service-worker.js的文本内容有立异,就会使用新的本子。可是有1些要留意:旧缓存文件的化解、新文件的缓存要在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,二,1,二,一,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地图