菜单

Service Worker初体验

2019年4月11日 - jQuery

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

原稿出处: AlloyTeam   

在201四年,W3C发布了service worker的草案,service
worker提供了不少新的力量,使得web app拥有与native
app相同的离线体验、新闻推送体验。
service worker是一段脚本,与web
worker1样,也是在后台运营。作为三个单身的线程,运行环境与日常脚本分裂,所以不能够直接参加web交互行为。native
app能够完成离线使用、音信推送、后台自动更新,service
worker的面世是多亏为了使得web app也可以享有类似的力量。

 

service worker可以:

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

正文以财富缓存为例,说宾博下service worker是何等工作的。

作用:

可以使你的采取先走访本地缓存财富,所以在离线状态时,在未有通过互连网收到到更加多的数量前,仍是可以够提供基本的法力。

生命周期

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

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

图中能够看来,2个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的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(UKugaL).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简单结合的2个小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 方法重回1个 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()
    创造了贰个响应对象的克隆,那么些目的在享有地点都是千篇1律的,不过存款和储蓄在一个见仁见智的变量中。防止频仍运用篡改了指标。

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是二个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能够回到自身的响应。

先是检缓存中是不是已经缓存了那么些请求,倘若有,就直接回到响应,就收缩了三遍网络请求。不然由service
workder发起请求,这时的service workder起到了几在那之中等代理的效益。

service worker请求的历程通过fetch
api实现,得到response对象现在举行过滤,查看是还是不是是图片文件,假使不是,就径直回到请求,不会缓存。

借使是图形,要先复制一份response,原因是request也许response对象属于stream,只好利用3次,之后壹份存入缓存,另1份发送给页面。
那正是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);
        }
      }));
    })
  );
});

标题一. 运作时刻

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,一,二,一,一,2….,原因是hitCounter并不曾一向留存,如若浏览器关闭了它,下次开发银行的时候hitCounter就赋值为0了
这么的事情导致调节和测试代码困难,当你更新1个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地图