菜单

Service Worker初体验

2019年4月7日 - CSS/CSS3

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

初稿出处: AlloyTeam   

在201肆年,W3C发表了service worker的草案,service
worker提供了好多新的力量,使得web app拥有与native
app相同的离线体验、新闻推送体验。
service worker是1段脚本,与web
worker1样,也是在后台运维。作为3个单身的线程,运营条件与常见脚本区别,所以不能够直接加入web交互行为。native
app能够完成离线使用、音信推送、后台自动更新,service
worker的出现是万幸为了使得web app也得以享有类似的力量。

 

service worker可以:

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

本文以财富缓存为例,说美素佳儿(Friso)下service worker是怎么样工作的。

作用:

能够使您的运用先拜访本地缓存财富,所以在离线状态时,在并未有经过网络收到到越来越多的多少前,还可以够提供基本的遵从。

生命周期

先来看一下三个service worker的运行周期

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

图中可以观望,1个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事件拦截请求,并且付诸自个儿的响应。
w3c提供了1个新的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作为中间纽带,使得八个域名依旧子域名下的多少个页面能够任意通讯。

此地是2个小的页面之间通讯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 方法再次回到3个 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 1样, 是暴光在 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代码。
依据前边的生命周期图,在1个新的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);
        })
    );
});

第2定义了需求缓存的公文数组cacheFile,然后在install事件中,缓存这一个文件。
evt是三个InstallEvent对象,继承自Extendable伊芙nt,在那之中的waitUntil()方法接收3个promise对象,直到那几个promise对象成功resolve之后,才会三番肆回运营service-worker.js。
caches是一个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对象今后举办过滤,查看是或不是是图片文件,假若不是,就直接重返请求,不会缓存。

若是是图片,要先复制一份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)
  );
});

归来的结果或然是不曾规律的:一,二,1,二,1,一,2….,原因是hitCounter并未直接存在,假诺浏览器关闭了它,下次运转的时候hitCounter就赋值为0了
那般的事务导致调节和测试代码困难,当你更新一个service
worker现在,唯有在开拓新页面以后才大概应用新的service
worker,在调节进度中时常等上1两分钟才会利用新的,相比抓狂。

参照 MDN

瑟维斯 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地图