菜单

Service Worker入门

2019年4月14日 - JavaScript

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

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

原生App拥有Web应用普通所不享有的富离线体验,定时的沉默寡言更新,新闻通知推送等效果。而新的Serviceworkers标准让在Web App上拥有这一个成效成为恐怕。

image

Service Worker 是什么?

二个 service worker
是一段运营在浏览器后台进程里的台本,它独立于当下页面,提供了这几个不要求与web页面交互的功能在网页背后悄悄执行的力量。在后天,基于它可以落成音讯推送,静默更新以及地理围栏等服务,不过当前它首先要全数的效用是阻止和拍卖网络请求,包罗可编程的响应缓存管理。

为啥说那些API是1个充足棒的API呢?因为它使得开发者能够协理尤其好的离线体验,它赋予开发者完全控制离线数据的能力。

在service worker提议在此之前,其它叁个提供开发者离线体验的API叫做App
Cache。然则App
Cache有个别局限性,例如它能够很简单地解决单页应用的标题,不过在多页应用上会很麻烦,而Serviceworkers的面世就是为了缓解App Cache的痛点。

下边详细说一下service worker有啥需求注意的地点:

尤其简的介

二零一八年始于火遍南北的 PWA 技术诞生处境有负重望,首要来源 safrai
对于这一技术帮忙不甚理想,不协助 mainfest 文件也不支持
service Worker

service worker 是三个优秀的 web Worker,因而他与页面通讯和 worker
是相同的,同样不可能访问 DOM。特殊在于他是由事件驱动的装有生命周期的
worker,并且能够阻止处理页面包车型大巴互连网请求(fetch),能够访问 cache
IndexDB

换言之 service Worker
能够让开发者本人控制管理缓存的剧情以及版本,为离线弱网环境下的 web
的周转提供了说不定,让 web 在体会上特别靠近 native。

Service Worker的生命周期

Service worker拥有2个完全独立于Web页面包车型地铁生命周期。

要让一个service
worker在您的网址上生效,你必要先在您的网页中注册它。注册二个service
worker之后,浏览器会在后台默默运维3个service worker的安装进度。

在安装进度中,浏览器会加载并缓存1些静态能源。要是具有的公文被缓存成功,service
worker就设置成功了。假诺有其他文件加载或缓存失利,那么安装进度就会失利,service
worker就不可能被激活(也即没能安装成功)。假如产生如此的难题,别担心,它会在下次再尝试安装。

当安装到位后,service
worker的下一步是激活,在那1品级,你还足以升级3个service
worker的版本,具体内容大家会在背后讲到。

在激活之后,service
worker将接管全部在协调管辖域范围内的页面,不过若是三个页面是刚刚注册了service
worker,那么它那二遍不会被接管,到下一回加载页面包车型大巴时候,service
worker才会生效。

当service
worker接管了页面之后,它或许有二种状态:要么被甘休以节约内部存款和储蓄器,要么会处理fetch和message事件,那七个事件分别发出于1个网络请求出现还是页面上发送了三个音讯。

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

图片 1

协作情状

safrai 已经于 2017年8月 开始了 service Worker 的开发。

image

最近浏览器PC补助意况如图

国内重大浏览器帮助意况

android 设备在 4.4 版本采纳 Chromium 作为基础,Chromium 在 40
对于 service worker 帮忙。国内浏览器包含微信浏览器在内基本已经支撑
service Worker 这为升级体验提供了恐怕。service workerHTTP2
越发配哦,在今后依据它能够兑现音信推送,静默更新以及地理围栏等劳务。

在大家早先写码在此以前

从这个品类地址拿到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权限一点都不小,所以要防患它自个儿被歹徒篡改利用——译者注)

Github
Pages
恰巧是HTTPS的,所以它是四个上佳的原生态实验田。

若是你想要让你的server协理HTTPS,你需求为您的server得到3个TLS证书。差异的server安装方法差别,阅读接济文书档案并经过Mozilla’s
SSL config
generator
摸底最好实践。

问询前的询问

webWorker
fetch
cache
promise

使用Service Worker

近期我们有了polyfill,并且解决了HTTPS,让大家看看究竟怎么用service
worker。

生命周期

image

Service Workermain.js
举行挂号,第一遍注册前会举办辨析,判断加载的文书是或不是在域名下,协议是不是为
HTTPS 的,通过那两点则成功注册。
service Worker 早先进入下一个生命周期状态 installinstall
完结后会触发 service Workerinstall 事件。 如果 install
成功则接下去是 activate情状, 然后那一个 service worker
才能接管页面。当事件 active 事件执行到位之后,此时 service Worker
有二种境况,壹种是 active,一种是 terminatedactive
是为了工作,terminated则为了节约内部存款和储蓄器。当新的 service Worker 处于
install/waitting 阶段,当前 service Worker 处于
terminated,就会时有爆发交接替换。或许能够经过调用 self.skipWaiting()
方法跳过等待。
被沟通掉的原来的 service WorkerRedundant 阶段,在 install 或者
activating 中断的也会跻身 Redundant 阶段。所以三个 Service Worker
脚本的生命周期有这样有些等级(从左往右):

[图表上传失利…(image-af3cfa-1511157771六一柒)]

何以注册和设置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 被注册。

1旦这几个service worker已经被登记过,浏览器会活动忽略上边包车型客车代码。

有1个须要特地表明的是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第3版被达成的时候,你也能够在chrome://serviceworker-internals中查看,它很有用,通过它可以最直观地熟悉service worker的生命周期,不过这个功能很快就会被移到chrome://inspect/#service-workers中。

您会发现这一个职能能够很便利地在三个模仿窗口中测试你的service
worker,那样您能够关闭和重复打开它,而不会潜移默化到您的新窗口。任何制造在模仿窗口中的注册服务和缓存在窗口被关门时都将消灭。

Install

install 存在中间态 installing 那个状态在 main.js
registration挂号对象中得以访问到。

/* In main.js */
// 重写 service worker 作用域到 ./
navigator.serviceWorker.register('./sw.js', {scope: './'}).then(function(registration) {  
    if (registration.installing) {
        // Service Worker is Installing
    }
})

安装时 service Workerinstall
事件被触发,那一般用于拍卖静态能源的缓存

service worker 缓存的静态能源

chrome PWA 演示实例

/* In sw.js */
self.addEventListener('install', function(event) {  
  event.waitUntil(
  // currentCacheName 对应调试工具中高亮位置,缓存的名称
  // 调用 `cache.open` 方法后才可以缓存文件
    caches.open(currentCacheName).then(function(cache) {
    // arrayOfFilesToCache 为存放缓存文件的数组
      return cache.addAll(arrayOfFilesToCache);
    })
  );
});

event.waitUntil() 方法接收3个 promise 对象, 如若那个 promise
对象 rejectedservice Worker 安装退步,状态变更为
Redundant。关于 cache 相关注明看下文。

Service Worker的装置步骤

在页面上实现登记手续之后,让大家把集中力转到service
worker的台本里来,在那里面,大家要形成它的设置步骤。

在最中央的例证中,你必要为install事件定义1个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. 开启3个缓存
  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获得1个promise并使用它来博取安装成本的时刻以及是或不是安装成功。

要是拥有的文书都被缓存成功了,那么service
worker就设置成功了。假若别的3个文本下载战败,那么安装步骤就会破产。这一个主意允许你依靠于你自身钦定的富有能源,然则那意味你须要特别严苛地决定哪些文件需求在装置步骤中被缓存。钦点了太多的文件的话,就会增添设置战败率。

上边只是1个简便的例证,你能够在install事件中实践此外操作如故甚至忽视install事件。

Installed / Waiting

设置达成待正在运转的 service Worker 交接的情状。
Service Worker registration 对象, 我们得以获得那个意况

/* In main.js */
navigator.serviceWorker.register('./sw.js').then(function(registration) {  
    if (registration.waiting) {
        // Service Worker is Waiting
    }
})

那是五个唤起用户更新的好机遇,可能能够静默更新。

怎么缓存和再次来到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的结果。那是3个卓殊不难的例子,使用具有在install步骤下被缓存的能源。

万1大家想要增量地缓存新的乞求,我们能够透过处理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. 添加3个callback到fetch请求的 .then 方法中
  2. 假如我们获取了二个response,大家开展如下的自笔者批评:
    1. 管教response是卓有作用的
    2. 反省response的图景是不是是200
    3. 保障response的档次是basic,那表示请求作者是同源的,非同源(即跨域)的呼吁也不能够被缓存。
  3. 要是大家经过了检查,clone本条请求。这么做的原由是假若response是3个Stream,那么它的body只能被读取1次,所以我们得将它克隆出来,壹份发给浏览器,一份发给缓存。

Activating

则状态成为 activating,触发 service workeractive 事件。

/* In sw.js */
self.addEventListener('activate', function(event) {  
  event.waitUntil(
    // Get all the cache names
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        // Get all the items that are stored under a different cache name than the current one
        cacheNames.filter(function(cacheName) {
          return cacheName != currentCacheName;
        }).map(function(cacheName) {
          // Delete the items
          return caches.delete(cacheName);
        })
      ); // end Promise.all()
    }) // end caches.keys()
  ); // end event.waitUntil()
});

install 事件中的 event.waitUntil 方法。当所收取的 promise
reject 那么 serviceWorker 进入 Redundant状态。

怎样翻新三个Service Worker

您的service
worker总有必要更新的那一天。当那1天来临的时候,你需求依据如下步骤来更新:

  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的时候立时执行它,那么依然在运转的旧版本的数据就坏了。

事先我们只行使了2个缓存,叫做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);
          }
        })
      );
    })
  );
});

Actived

activting成功后,这时 service Worker 接管了全副页面状态变成
acticed
那几个意况大家能够阻挡请求和音信。

/* In sw.js */

self.addEventListener('fetch', function(event) {  
  // Do stuff with fetch events
});

self.addEventListener('message', function(event) {  
  // Do stuff with postMessages received from document
});

拍卖边界和填坑

这一节内容相比新,有那些待定细节。希望那1节非常的慢就不须要讲了(因为标准会处理那么些问题——译者注),不过现在,那一个剧情依然应该被提一下。

Redundant

service Workerinstall active进程中处错误也许,被新的
service Worker 替换状态会变成 Redundant

如假若后1种状态,则该 worker 仍旧控制这几个页面。

值得注意的是已经 installservice worker
页面关闭后再打开不会触发 install 事件,可是会另行挂号。越多参考文章
研究 瑟维斯 Worker
「生命周期」

若是设置失利了,没有很优雅的主意获取通报

一经一个worker被注册了,不过并未有出现在chrome://inspect/#service-workers或chrome://serviceworker-internals,那么很可能因为异常而安装失败了,或者是产生了一个被拒绝的的promise给event.waitUtil。

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

请求处理

处于 actived 阶段的 service Worker 能够阻碍页面发出的
fetch,也得以产生fetch恳请,能够将请求和响应缓存在
cache里,也足以将 responsecache 中取出。

fetch()最近仅支持Service Workers

fetch立即补助在页面上运用了,不过最近的Chrome落成,它还只帮忙service
worker。cache
API也将要在页面上被帮衬,然而如今截至,cache也还只辛亏service
worker中用。

缓存使用政策

所以得以依照使用的场所,使用缓存的 response
给到页面减弱请求及时响应,亦只怕将请求重返的结果更新到缓存,在接纳离线时回来给页面。那正是以下的有余政策。

  1. 网络优先: 从网络获取, 退步或许逾期再品尝从缓存读取
  2. 缓存优先: 从缓存获取,
    缓存插叙不到再品尝从互联网抓取,在上文中的代码块便是该种策略的兑现。
  3. 最快: 同时询问缓存和网络, 再次回到开首获得的
  4. 仅限网络: 仅从网络获取
  5. 仅限缓存: 仅从缓存获取

fetch()的暗中同意参数

当您利用fetch,缺省级地区级,请求不会带上cookies等证据,要想带上的话,须要:

JavaScript

fetch(url, { credentials: ‘include’ })

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

那样设计是有理由的,它比XHENVISION的在同源下私下认可发送凭据,但跨域时抛弃凭据的条条框框要来得好。fetch的表现更像别的的CO中华VS请求,例如<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

示例

fetch 基于stream 的 ,因此 response & request
一旦被消费则无从恢复生机,所以这边在缓存的时候须求选择 clone
方法在开销前复制一份。

self.addEventListener('fetch', function(event) {
// 只对 get 类型的请求进行拦截处理
  if (event.request.method !== 'GET') {
    console.log('WORKER: fetch event ignored.', event.request.method, event.request.url);
    return;
  }
  event.respondWith(
  // 缓存中匹配请求
    caches.match(event.request)
      .then(function(response) {
        if (response) {
          return response;
        }

        // 因为 event.request 流已经在 caches.match 中使用过一次,
        // 那么该流是不能再次使用的。我们只能得到它的副本,拿去使用。
        var fetchRequest = event.request.clone();

        // fetch 的通过信方式,得到 Request 对象,然后发送请求
        return fetch(fetchRequest).then(
          function(response) {
            // 检查是否成功
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // 如果成功,该 response 一是要拿给浏览器渲染,而是要进行缓存。
            // 不过需要记住,由于 caches.put 使用的是文件的响应流,一旦使用,
            // 那么返回的 response 就无法访问造成失败,所以,这里需要复制一份。
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});

Non-CO大切诺基S暗许不扶助

暗中同意意况下,从第三方U君越L跨域得到3个财富将会失利,除非对方补助了CO奇骏S。你能够加上一个non-COTucsonS选项到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;

Register 时机

service Worker 将加剧对 CPU
时间和内部存款和储蓄器的争用,从而影响浏览器渲染以及网页的互相。Chrome 团队的开发者
Jeff Posnick 实践证明在突显动画时期注册 service Worker
会导致低端移动装备出现卡顿,因而在那种现象下延后登记或等越来越好的用户体验。

//Bad
window.addEventListener('DOMContentLoaded', function() {
    navigator.serviceWorker.register('/sw.js').then(function(registration) {

    }).catch(function(err) {

    }); 
  });


// Good
if ('serviceWorker' in navigator) {
// 判断浏览器支持情况
  window.addEventListener('load', function() {
  // 页面所有资源加载完成后注册
    navigator.serviceWorker.register('/service-worker.js');
  });
}

不过当你选拔 clients.claim()service Worker 控制全数

处理响应式图片

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

在service worker中,你想要在install步骤缓存3个图片,你有以下两种选用:

  1. 安装具有的<picture>元素或者将被请求的srcset属性。
  2. 安装单1的low-res版本图片
  3. 安装单一的high-res版本图片

正如好的方案是2或三,因为假设把全部的图样都给下载下来存着有点浪费内部存款和储蓄器。

倘使你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互连网上下载high-res的本子,不过假设high-res版本下载失败以来,就照样用low-res版本。这几个想法很好也值得去做,可是有3个题材:

万一大家有上边三种图片:

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" />

若是我们在1个二x的突显形式下,浏览器会下载image-二x.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类似的思路去解决。

install 事件中静态财富缓存

service Workerinstall
事件中缓存文件进度中,当在那之中3个文本加载失利,则 install
退步。因而能够对要缓存的文书实行个别,一定要加载的,和允许加载败北的,对于同意加载战败的公文。

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('mygame-core-v1').then(function(cache) {
    // 不稳定文件或大文件加载
      cache.addAll(
        //...
      );
      // 稳定文件或小文件加载
      return cache.addAll(
        // core assets & levels 1-10
      );
    })
  );
});

改变URL Hash的Bug

在M40版本中留存一个bug,它会让页面在改动hash的时候造成service
worker结束工作。

您可以在此地找到愈来愈多相关的新闻: https://code.google.com/p/chromium/issues/detail?id=433708

处理请求中离线情状

service Worker 发送请求时,捕获至极,并赶回页面2个 response
公告页面或者离线。

function unableToResolve () {
  /* 
    当代码执行到这里,说明请求无论是从缓存还是走网络,都无法得到答复,这个时机,我们可以返回一个相对友好的页面,告诉用户,你可能离线了。
  */
  console.log('WORKER: fetch request failed in both cache and network.');
  return new Response('<h1>Service Unavailable</h1>', {
    status: 503,
    statusText: 'Service Unavailable',
    headers: new Headers({
      'Content-Type': 'text/html'
    })
  });
}
fetch(event.request).then(fetchedFromNetwork, unableToResolve).catch(unableToResolve);

更多内容

此间有一对相关的文书档案能够参考:https://jakearchibald.github.io/isserviceworkerready/resources.html

引进开关机制

开关是在饿了么实践经验里建议降级方案,通过向后端请求2个是否降级的接口,倘若降级则打消掉已经注册的service Worker。那里要留心不要缓存这么些开关请求。为了有利于难题排查,能够安装二个debug 形式(在 url 添加有个别字符)。

取得救助

设若你遇见麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家霎时跟进和不择手段帮忙您消除难点。

赞 2 收藏
评论

图片 4

谬误监察和控制

self.addEventListener('error', event => {
  // 上报错误信息
  // 常用的属性:
  // event.message
  // event.filename
  // event.lineno
  // event.colno
  // event.error.stack
})
// 捕获 promise 错误
self.addEventListener('unhandledrejection', event => {
  // 上报错误信息
  // 常用的属性:
  // event.reason
})

那八个事件都只能在 worker 线程的 initial
生命周期里登记。(不然会破产,控制台可观看警告)

谷歌(Google) 开发工具助力 service worker 开发

Google 提供了 sw-toolboxsw-precache 五个工具方便高效生成
service-worker.js 文件:

更多[参考小说]([PWA 入门: 精通和创办 Service Worker 脚本])

注意事项

参考

MDN
Service Worker
lifecycle

service worker
note

update service
worker

chrom service worker
sample

PWA 入门: 精通和开创 Service Worker
脚本

PWA
在饿了么的实践经验

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图