译文出处

日期:2019-11-17编辑作者:北京pk赛车网站-web前端

Service Worker入门

2015/03/26 · JavaScript · Service Worker

原稿出处: Matt Gaunt   译文出处:[w3ctech

  • 十年踪迹]()   

原生App具有Web应用普通所不富有的富离线体验,准时的默默无言更新,音讯公告推送等功效。而新的Serviceworkers标准让在Web App上有着那个效应成为恐怕。

Service Worker 是什么?

一个 service worker 是风华正茂段运维在浏览器后台进度里的台本,它独自于这段时间页面,提供了这几个无需与web页面人机联作的机能在网页背后悄悄试行的手艺。在前天,基于它能够兑现消息推送,静默更新以致地理围栏等服务,不过近日它首先要享有的功用是阻挠和拍卖网络诉求,包罗可编制程序的响应缓存管理。

为啥说那些API是二个相当棒的API呢?因为它使得开荒者能够支持极度好的离线体验,它付与开拓者完全调整离线数据的本事。

在service worker提议此前,别的多个提供开垦者离线体验的API叫做App Cache。不过App Cache某个局限性,举个例子它能够超级轻便地消亡单页应用的题目,不过在多页应用上会很麻烦,而Serviceworkers的面世正是为了消除App Cache的痛点。

下边详细说一下service worker有何样必要在乎之处:

  • 它是JavaScript Worker,所以它不能直接操作DOM。可是service worker能够经过postMessage与页面之间通讯,把新闻布告给页面,假若供给的话,让页面本人去操作DOM。
  • Serviceworker是二个可编制程序的网络代理,允许开拓者调控页面上拍卖的互联网诉求。
  • 在不被使用的时候,它会自个儿终止,而当它再也被用到的时候,会被重复激活,所以您不能够信任于service worker的onfecth和onmessage的管理函数中的全局状态。要是你想要保存一些长久化的新闻,你能够在service worker里使用IndexedDB API。
  • Serviceworker多量使用promise,所以倘若你不打听怎么是promise,那您必要先读书这篇文章。

Service Worker的生命周期

Service worker具有一个截然独立于Web页面的生命周期。

要让叁个service worker在你的网址上生效,你要求先在您的网页中登记它。注册叁个service worker之后,浏览器会在后台默默运营一个service worker的设置进度。

在设置进度中,浏览器会加载并缓存一些静态能源。纵然具有的文件被缓存成功,service worker就设置成功了。要是有其余文件加载或缓存战败,那么安装进度就能停业,service worker就不能够被激活(也即未能安装成功卡塔尔。纵然发生如此的难题,别忧郁,它会在下一次再品尝安装。

当安装到位后,service worker的下一步是激活,在此一品级,你还是能够升高多少个service worker的本子,具体内容大家会在末端讲到。

在激活之后,service worker将接管全部在投机管辖域范围内的页面,可是如若多少个页面是刚刚注册了service worker,那么它这二回不会被接管,到下二遍加载页面包车型地铁时候,service worker才会生效。

当service worker接管了页面之后,它只怕有二种情景:要么被结束以节省里部存款和储蓄器,要么会管理fetch和message事件,那多个事件分别产生于一个网络央求现身照旧页面上发送了多个新闻。

下图是二个简化了的service worker初次安装的生命周期:

图片 1

在我们开头写码以前

从这个品种地址拿到chaches polyfill。

这个polyfill支持CacheStorate.match,Cache.add和Cache.addAll,而现在Chrome M40实现的Cache API还并未有支持那些方法。

将dist/serviceworker-cache-polyfill.js放到你的网址中,在service worker中通过importScripts加载进来。被service worker加载的本子文件会被活动缓存。

JavaScript

importScripts('serviceworker-cache-polyfill.js');

1
importScripts('serviceworker-cache-polyfill.js');

需要HTTPS

在开拓阶段,你能够因此localhost使用service worker,不过倘若上线,就要求你的server帮衬HTTPS。

您能够透过service worker要挟连接,伪造和过滤响应,特别逆天。固然你能够约束本身不干坏事,也有人想干坏事。所感到了防御旁人使坏,你必须要在HTTPS的网页上登记service workers,这样我们才方可幸免加载service worker的时候不被歹徒点窜。(因为service worker权限一点都不小,所以要防备它自己被歹徒窜改利用——译者注卡塔 尔(英语:State of Qatar)

Github Pages刚刚是HTTPS的,所以它是八个卓越的后天性实验田。

假诺你想要令你的server协助HTTPS,你需求为您的server获得四个TLS证书。分裂的server安装方法区别,阅读帮忙文书档案并经过Mozilla’s SSL config generator叩问最好实施。

使用Service Worker

现行反革命大家有了polyfill,而且消除了HTTPS,让大家看看毕竟怎么用service worker。

如何注册和安装service worker

要安装service worker,你必要在你的页面上注册它。这么些手续告诉浏览器你的service worker脚本在何地。

JavaScript

if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }

1
2
3
4
5
6
7
8
9
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    // Registration was successful
    console.log('ServiceWorker registration successful with scope: ',    registration.scope);
  }).catch(function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
}

地点的代码检查service worker API是不是可用,假若可用,service worker /sw.js 被注册。

举例那几个service worker已经被注册过,浏览器会自动忽视上边的代码。

有叁个内需特意表明的是service worker文件的路线,你鲜明注意到了在这里个例子中,service worker文件被放在这里个域的根目录下,那代表service worker和网址同源。换句话说,那一个service work将会收下那些域下的持有fetch事件。假设自个儿将service worker文件注册为/example/sw.js,那么,service worker只能收到/example/路径下的fetch事件(例如: /example/page1/, /example/page2/)。

当今您能够到 chrome://inspect/#service-workers 检查service worker是否对你的网站启用了。

图片 2

当service worker第大器晚成版被落成的时候,你也足以在chrome://serviceworker-internals中查看,它很有用,通过它可以最直观地熟悉service worker的生命周期,不过这个功能很快就会被移到chrome://inspect/#service-workers中。

您会发掘那么些作用能够很有益于地在四个模拟窗口中测量检验你的service worker,那样你能够关闭和重新张开它,而不会影响到您的新窗口。任何创制在模仿窗口中的注册服务和缓存在窗口被关闭时都将消失。

Service Worker的安装步骤

在页面上成功登记手续之后,让我们把注意力转到service worker的剧本里来,当中,大家要做到它的安装步骤。

在最中央的事例中,你须要为install事件定义四个callback,并操纵怎么样文件你想要缓存。

JavaScript

// The files we want to cache var urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; // Set the callback for the install step self.addEventListener('install', function(event) { // Perform install steps });

1
2
3
4
5
6
7
8
9
10
11
// The files we want to cache
var urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];
 
// Set the callback for the install step
self.addEventListener('install', function(event) {
    // Perform install steps
});

在我们的install callback中,大家须求施行以下步骤:

  1. 翻开四个缓存
  2. 缓存大家的文书
  3. 决定是还是不是具备的能源是或不是要被缓存

JavaScript

var CACHE_NAME = 'my-site-cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; self.addEventListener('install', function(event) { // Perform install steps event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];
 
self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

下边包车型客车代码中,大家经过caches.open展开大家内定的cache文件名,然后大家调用cache.addAll并传播我们的文本数组。那是由此多元promise(caches.open 和 cache.addAll卡塔尔国完结的。event.waitUntil获得一个promise并行使它来博取安装花费的岁月以致是不是安装成功。

借使具有的文书都被缓存成功了,那么service worker就安装成功了。若是其余一个文书下载战败,那么安装步骤就能停业。那一个方法允许你依赖于您自身钦点的有着财富,不过那意味你供给极度严苛地操纵哪些文件须要在安装步骤中被缓存。内定了太多的文书的话,就可以扩展设置退步率。

上边只是多少个轻便易行的例子,你能够在install事件中进行其它操作如故以至忽略install事件。

什么样缓存和重返Request

你早就设置了service worker,你今后得以回到您缓存的倡议了。

当service worker棉被服装置成功还要客户浏览了另三个页面也许刷新了当下的页面,service worker将上马收受到fetch事件。上边是贰个例子:

JavaScript

self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // Cache hit - return response if (response) { return response; } return fetch(event.request); } ) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }
 
        return fetch(event.request);
      }
    )
  );
});

上边的代码里我们定义了fetch事件,在event.respondWith里,大家传入了二个由caches.match发生的promise.caches.match 查找request中被service worker缓存命中的response。

就算我们有二个命中的response,大家回去被缓存的值,不然大家回到三个实时从互联网乞请fetch的结果。那是二个特别轻便的事例,使用全数在install步骤下被缓存的财富。

要是我们想要增量地缓存新的伸手,大家能够透过拍卖fetch须要的response并且拉长它们到缓存中来兑现,譬如:

JavaScript

self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // Cache hit - return response if (response) { return response; } // IMPORTANT: Clone the request. A request is a stream and // can only be consumed once. Since we are consuming this // once by cache and once by the browser for fetch, we need // to clone the response var fetchRequest = event.request.clone(); return fetch(fetchRequest).then( function(response) { // Check if we received a valid response if(!response || response.status !== 200 || response.type !== 'basic') { return response; } // IMPORTANT: Clone the response. A response is a stream // and because we want the browser to consume the response // as well as the cache consuming the response, we need // to clone it so we have 2 stream. var responseToCache = response.clone(); caches.open(CACHE_NAME) .then(function(cache) { cache.put(event.request, responseToCache); }); return response; } ); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }
 
        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();
 
        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }
 
            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have 2 stream.
            var responseToCache = response.clone();
 
            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });
 
            return response;
          }
        );
      })
    );
});

代码里我们所做政工包含:

  1. 丰硕三个callback到fetch乞请的 .then 方法中
  2. 比方大家收获了一个response,我们开展如下的反省:
    1. 确定保障response是一蹴而就的
    2. 反省response的情景是不是是200
    3. 确认保证response的门类是basic,那意味着央浼小编是同源的,非同源(即跨域卡塔尔国的央求也不可能被缓存。
  3. 若是大家透过了反省,clone其风流倜傥央浼。这么做的缘由是生机勃勃旦response是三个Stream,那么它的body只好被读取三回,所以我们得将它克隆出来,意气风发份发给浏览器,后生可畏份发给缓存。

什么改正二个瑟维斯 Worker

你的service worker总有亟待创新的那一天。当那一天来到的时候,你供给依据如下步骤来更新:

  1. 更新您的service worker的JavaScript文件
    1. 当顾客浏览你的网址,浏览器尝试在后台下载service worker的台本文件。只要服务器上的文本和本土文件有三个字节分裂,它们就被判断为供给更新。
  2. 更新后的service worker将起来运行,install event被重新触发。
  3. 在此个小时节点上,当前页目生效的如故是老版本的service worker,新的servicer worker将跻身”waiting”状态。
  4. 时下页面被关门之后,老的service worker进度被杀掉,新的servicer worker正式生效。
  5. 设若新的service worker生效,它的activate事件被触发。

代码更新后,常常需求在activate的callback中实施二个管理cache的操作。因为您会须要消亡掉以前旧的数码。大家在activate并不是install的时候实施那一个操作是因为假设大家在install的时候马上试行它,那么照旧在运作的旧版本的数据就坏了。

早前大家只利用了三个缓存,叫做my-site-cache-v1,其实我们也可以使用多个缓存的,例如一个给页面使用,一个给blog的内容提交使用。这意味着,在install步骤里,我们可以创建两个缓存,pages-cache-v1和blog-posts-cache-v1,在activite步骤里,我们可以删除旧的my-site-cache-v1。

上面包车型客车代码能够循环全部的缓存,删除掉全数不在白名单中的缓存。

JavaScript

self.addEventListener('activate', function(event) { var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1']; event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.map(function(cacheName) { if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.addEventListener('activate', function(event) {
 
  var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1'];
 
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

拍卖边界和填坑

那意气风发节内容相比新,有成都百货上千待定细节。希望这大器晚成节不慢就无需讲了(因为标准会处理那一个难点——译者注卡塔尔国,但是现在,这么些内容照旧应当被提一下。

假使设置战败了,没有很高雅的艺术得到通报

如果叁个worker被登记了,不过从未出未来chrome://inspect/#service-workers或chrome://serviceworker-internals,那么很可能因为异常而安装失败了,或者是产生了一个被拒绝的的promise给event.waitUtil。

要减轻那类难点,首先到 chrome://serviceworker-internals检查。打开开发者工具窗口准备调试,然后在你的install event代码中添加debugger;语句。这样,通过断点调试你更容易找到问题。

fetch()方今仅扶植Service Workers

fetch马上支持在页面上应用了,不过当前的Chrome达成,它还只协助service worker。cache API也将在要页面上被援助,不过近来甘休,cache也还只可以在service worker中用。

fetch()的私下认可参数

当你利用fetch,缺省级地区级,央浼不会带上cookies等凭证,要想带上的话,需求:

JavaScript

fetch(url, { credentials: 'include' })

1
2
3
fetch(url, {
  credentials: 'include'
})

如此那般设计是有理由的,它比XHENVISION的在同源下默许发送凭据,但跨域时放弃凭据的法则要来得好。fetch的行为更像此外的CO奇骏S诉求,比方<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

Non-CO奥迪Q7S私下认可不协理

暗许情状下,从第三方U路虎极光L跨域得到二个资源将会倒闭,除非对方扶植了COKoleosS。你能够增添一个non-CO奥德赛S选项到Request去制止战败。代价是那样做会重回叁个“不透明”的response,意味着你无法意识到这一个央浼究竟是马到功成了依旧诉讼失败了。

JavaScript

cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) { return new Request(urlToPrefetch, { mode: 'no-cors' }); })).then(function() { console.log('All resources have been fetched and cached.'); });

1
2
3
4
5
cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {
  return new Request(urlToPrefetch, { mode: 'no-cors' });
})).then(function() {
  console.log('All resources have been fetched and cached.');
});

fetch()不依据30x重定向标准

不佳,重定向在fetch()中不会被触发,这是时下版本的bug;

管理响应式图片

img的srcset属性或然<picture>标签会根据情况从浏览器或者网络上选择最合适尺寸的图片。

在service worker中,你想要在install步骤缓存一个图形,你有以下三种接收:

  1. 设置具备的<picture>元素或者将被请求的srcset属性。
  2. 设置单后生可畏的low-res版本图片
  3. 设置单豆蔻梢头的high-res版本图片

正如好的方案是2或3,因为如若把具有的图片都给下载下来存着有一点浪费内部存款和储蓄器。

只要你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互连网上下载high-res的本子,可是即便high-res版本下载失败以来,就依然用low-res版本。这几个主见很好也值得去做,但是有八个标题:

假定我们有上边三种图片:

Screen Density Width Height
1x 400 400
2x 800 800

HTML代码如下:

JavaScript

<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" />

1
<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" />

若果大家在贰个2x的显示情势下,浏览器会下载image-2x.png,倘若大家离线,你能够读取早先缓存并重返image-src.png替代,如若早前它曾经被缓存过。就算如此,由于后天的格局是2x,浏览器会把400X400的图形显示成200X200,要幸免这些主题素材即就要图片的样式上安装宽高。

JavaScript

<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" style="width:400px; height: 400px;" />

1
2
<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x"
style="width:400px; height: 400px;" />

图片 3

<picture>标签情况更复杂一些,难度取决于你是如何创建和使用的,但是可以通过与srcset类似的思路去解决。

改变URL Hash的Bug

在M40版本中存在一个bug,它会让页面在更换hash的时候产生service worker甘休工作。

您能够在这里边找到更加的多相关的音讯: 

愈来愈多内容

那边有局地相关的文书档案可以参照:

赢得扶植

假定您赶过麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家及时跟进和不择花招援救您消除难题。

赞 2 收藏 评论

图片 4

本文由北京pk赛车官网下载发布于北京pk赛车网站-web前端,转载请注明出处:   译文出处

关键词:

使用 Service Worker 做一个 PWA 离线网页应用

使用 Service Worker 做一个 PWA 离线网页应用 2017/10/09 · JavaScript· PWA, ServiceWorker 原文出处:人人网FED博客    在上一篇...

详细>>

利用 Service worker 创建一个非常简单的离线页面

利用 Service worker 创建一个非常简单的离线页面 2016/06/07 · JavaScript· 1 评论 · ServiceWorker 本文由 伯乐在线 -刘健超-J....

详细>>

用户可通过以下三种方式操作触发

前端本地文件操作与上传 2017/12/07 · JavaScript· 1 评论 ·文件 原文出处:人人网FED博客    前端无法像原生APP一样直接...

详细>>

indexedDB 基本使用

indexedDB 基本使用 2017/12/14 · 基础技术 ·1 评论 ·IndexedDB 原文出处:党黎明    indexedDB 简介: indexedDB 是一种使用浏览...

详细>>