菜单

Service Worker 从入门到进阶

2019年4月8日 - Json

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

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

原生App拥有Web应用壹般所不持有的富离线体验,定时的沉默更新,音信布告推送等功效。而新的Serviceworkers标准让在Web App上独具这几个职能成为或许。

image

Service Worker 是什么?

七个 service worker
是1段运维在浏览器后台进度里的本子,它独立于当下页面,提供了那些不须求与web页面交互的功能在网页背后悄悄执行的力量。在明日,基于它能够完毕新闻推送,静默更新以及地理围栏等服务,可是当前它首先要享有的职能是阻止和拍卖网络请求,包含可编制程序的响应缓存管理。

干什么说这一个API是八个百般棒的API呢?因为它使得开发者能够支撑特别好的离线体验,它赋予开发者完全控制离线数据的能力。

在service worker提议在此以前,别的一个提供开发者离线体验的API叫做App
Cache。然则App
Cache有个别局限性,例如它能够很容易地化解单页应用的题材,可是在多页应用上会很劳累,而Serviceworkers的面世便是为了缓解App Cache的痛点。

上面详细说一下service worker有哪些须要小心的地方:

尤其简的介

二〇一八年开始火遍南北的 PWA 技术诞生情形有负重望,重要来源 safrai
对于这一技术协助不甚美好,不帮助 mainfest 文件也不补助
service Worker

service worker 是2个例外的 web Worker,因而他与页面通讯和 worker
是均等的,同样不可能访问 DOM。特殊在于他是由事件驱动的全体生命周期的
worker,并且能够阻止处理页面包车型地铁网络请求(fetch),能够访问 cache
IndexDB

换言之 service Worker
能够让开发者自个儿说了算管理缓存的内容以及版本,为离线弱网环境下的 web
的运作提供了也许,让 web 在体验上尤为亲临其境 native。

Service Worker的生命周期

Service worker拥有贰个全然独立于Web页面包车型客车生命周期。

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

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

当安装到位后,service
worker的下一步是激活,在那1阶段,你还是能够升官一个service
worker的本子,具体内容我们会在前边讲到。

在激活之后,service
worker将接管全体在和谐管辖域范围内的页面,可是假若一个页面是刚刚注册了service
worker,那么它那壹回不会被接管,到下3回加载页面的时候,service
worker才会生效。

当service
worker接管了页面之后,它可能有两种状态:要么被截至以节省外部存款和储蓄器,要么会处理fetch和message事件,那多个事件分别产生于一个互联网请求出现照旧页面上发送了三个音信。

下图是二个简化了的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拿到叁个TLS证书。分歧的server安装方法不一致,阅读扶助文书档案并经过Mozilla’s
SSL config
generator
问询最棒实践。

打听前的垂询

webWorker
fetch
cache
promise

使用Service Worker

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

生命周期

image

Service Workermain.js
进行注册,第3次注册前会实行辨析,判断加载的文书是还是不是在域名下,协议是不是为
HTTPS 的,通过那两点则成功注册。
service Worker 初始进入下1个生命周期状态 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-af叁cfa-1511157771陆1七)]

哪些注册和装置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文件的不2诀要,你早晚留神到了在那几个事例中,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第2版被完结的时候,你也足以在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
事件被触发,那1般用于拍卖静态财富的缓存

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() 方法接收1个 promise 对象, 固然那么些 promise
对象 rejectedservice Worker 安装退步,状态变更为
Redundant。关于 cache 相关表明看下文。

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获得1个promise并利用它来赢得安装开销的时辰以及是不是安装成功。

比方全数的文书都被缓存成功了,那么service
worker就安装成功了。借使别的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
    }
})

那是3个唤起用户更新的好机会,或然能够静默更新。

怎么着缓存和重返Request

您曾经设置了service worker,你未来能够回去您缓存的呼吁了。

当service
worker被安装成功还要用户浏览了另三个页面或许刷新了脚下的页面,service
worker将上马接到到fetch事件。下边是3个事例:

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步骤下被缓存的能源。

比方大家想要增量地缓存新的乞请,我们得以经过处理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是1个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状态。

如何翻新2个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
});

拍卖边界和填坑

那一节内容相比较新,有众多待定细节。希望那一节非常快就不须求讲了(因为标准会处理这么些标题——译者注),然则以后,那些剧情照旧应当被提一下。

Redundant

service Workerinstall active经过中处错误恐怕,被新的
service Worker 替换状态会变成 Redundant

假假诺后壹种景况,则该 worker 照旧控制那个页面。

值得注意的是一度 installservice worker
页面关闭后再打开不会触发 install 事件,但是会重新登记。越来越多参考小说
探索 Service Worker
「生命周期」

若果设置失利了,未有很优雅的诀要获取通报

假如3个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’
})

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

示例

fetch 基于stream 的 ,因此 response & request
一旦被消费则不可能恢复生机,所以那边在缓存的时候须要利用 clone
方法在消费前复制1份。

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宝马X3S暗中同意不扶助

暗中认可景况下,从第贰方UWranglerL跨域获得一个能源将会破产,除非对方协助了COCRUISERS。你能够增加贰个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;

Register 时机

service Worker 将深化对 CPU
时间和内部存款和储蓄器的争用,从而影响浏览器渲染以及网页的相互。Chrome 团队的开发者
杰夫 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步骤缓存三个图片,你有以下二种选取:

  1. 设置具有的<picture>元素或者将被请求的srcset属性。
  2. 设置单1的low-res版本图片
  3. 设置单1的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-二x.png,如若大家离线,你能够读取从前缓存并赶回image-src.png替代,借使从前它早已被缓存过。纵然如此,由于今后的情势是二x,浏览器会把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
事件中缓存文件进程中,当在那之中二个文本加载退步,则 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 发送请求时,捕获非凡,并回到页面一个 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

引进开关机制

开关是在饿了么实践经验里建议降级方案,通过向后端请求二个是还是不是降级的接口,要是降级则打消掉已经注册的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
生命周期里登记。(不然会失败,控制台可旁观警告)

谷歌 开发工具助力 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地图