菜单

Service Worker入门

2019年4月6日 - JavaScript

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

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

原生App拥有Web应用壹般所不持有的富离线体验,定时的沉默更新,音信公告推送等功用。而新的Serviceworkers标准让在Web App上存有这个意义成为恐怕。

image

Service Worker 是什么?

三个 service worker
是一段运维在浏览器后台进度里的本子,它独立于当下页面,提供了那些不供给与web页面交互的效果在网页背后悄悄执行的力量。在未来,基于它能够达成音讯推送,静默更新以及地理围栏等劳务,不过当前它首先要负有的效益是阻挠和处理网络请求,包涵可编制程序的响应缓存管理。

为何说那些API是2个丰富棒的API呢?因为它使得开发者能够支撑更好的离线体验,它赋予开发者完全控制离线数据的力量。

在service worker建议在此之前,其它2个提供开发者离线体验的API叫做App
Cache。可是App
Cache有个别局限性,例如它能够很简单地缓解单页应用的难点,不过在多页应用上会很麻烦,而瑟维斯workers的产出即是为了化解App Cache的痛点。

上边详细说一下service worker有如何必要专注的地点:

尤其简的介

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

service worker 是一个破例的 web Worker,由此他与页面通讯和 worker
是同等的,同样不能够访问 DOM。特殊在于她是由事件驱动的有着生命周期的
worker,并且能够阻碍处理页面包车型大巴互连网请求(fetch),能够访问 cache
IndexDB

换言之 service Worker
能够让开发者本身说了算管理缓存的剧情以及版本,为离线弱网环境下的 web
的运营提供了或然,让 web 在体验上特别贴近 native。

瑟维斯 Worker的生命周期

Service worker拥有3个完全部独用立于Web页面包车型大巴生命周期。

要让1个service
worker在你的网址上生效,你供给先在您的网页中登记它。注册3个service
worker之后,浏览器会在后台默默运转一个service worker的设置进程。

在设置进度中,浏览器会加载并缓存一些静态财富。假使拥有的文书被缓存成功,service
worker就设置成功了。假若有其余文件加载或缓存退步,那么安装进程就会破产,service
worker就不可能被激活(也即没能安装成功)。倘诺爆发如此的难点,别担心,它会在下次再品尝安装。

当安装达成后,service
worker的下一步是激活,在那壹阶段,你还足以荣升3个service
worker的版本,具体内容我们会在前面讲到。

在激活之后,service
worker将接管全数在协调管辖域范围内的页面,不过假如二个页面是刚刚注册了service
worker,那么它那三次不会被接管,到下1次加载页面包车型客车时候,service
worker才会生效。

当service
worker接管了页面之后,它大概有二种情景:要么被终止以节省外部存款和储蓄器,要么会处理fetch和message事件,那五个事件分别发生于二个互连网请求出现依然页面上发送了多个音讯。

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

图片 1

相配情形

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

image

脚下浏览器PC帮忙景况如图

境内第1浏览器补助意况

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获得1个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
有二种情况,1种是 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 被注册。

壹经那些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中。

您会发现那一个效用能够很便宜地在3个效仿窗口中测试你的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() 方法接收三个 promise 对象, 借使那几个 promise
对象 rejectedservice Worker 安装退步,状态变更为
Redundant。关于 cache 相关认证看下文。

Service Worker的安装步骤

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

在最中央的事例中,你须求为install事件定义2个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就设置成功了。假使其余三个文书下载战败,那么安装步骤就会战败。那个法子允许你依靠于您本人钦定的装有财富,然而那象征你须要10分一笔不苟地操纵哪些文件必要在安装步骤中被缓存。钦命了太多的文书的话,就会增添设置退步率。

地点只是3个简单的事例,你能够在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事件。下边是三个例证:

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。

假定大家有1个命中的response,大家重回被缓存的值,否则大家回来2个实时从网络请求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. 假若大家赢得了3个response,我们进行如下的反省:
    1. 担保response是实用的
    2. 自作者批评response的景色是或不是是200
    3. 担保response的项目是basic,这意味着请求笔者是同源的,非同源(即跨域)的请求也无法被缓存。
  3. 假设大家经过了检查,clone本条请求。这么做的来头是假如response是二个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天来到的时候,你必要依据如下步骤来更新:

  1. 立异您的service worker的JavaScript文件
    1. 当用户浏览你的网站,浏览器尝试在后台下载service
      worker的剧本文件。只要服务器上的文书和地面文件有3个字节区别,它们就被判定为索要更新。
  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的时候实施那个操作是因为1旦大家在install的时候马上执行它,那么依旧在运作的旧版本的多寡就坏了。

前面大家只使用了3个缓存,叫做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
「生命周期」

即使设置失利了,未有很优雅的点子取得通报

就算2个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’
})

这么设计是有理由的,它比XH奔驰G级的在同源下私下认可发送凭据,但跨域时舍弃凭据的规则要来得好。fetch的一言一行更像其它的CO纳瓦拉S请求,例如<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-COOdysseyS暗中同意不扶助

默许意况下,从第二方UEnclaveL跨域获得贰个能源将会失利,除非对方扶助了COOdysseyS。你可以添加1个non-CO昂CoraS选项到Request去防止失利。代价是那般做会回到3个“不透明”的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. 安装单一的low-res版本图片
  3. 安装单1的high-res版本图片

正如好的方案是贰或三,因为假使把具有的图样都给下载下来存着有点浪费内部存储器。

若果你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从互联网上下载high-res的版本,然而1旦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" />

万壹大家在叁个二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
事件中缓存文件进程中,当个中二个文本加载战败,则 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);

愈来愈多内容

那边有1部分有关的文书档案能够参考:https://jakearchibald.github.io/isserviceworkerready/resources.html

引进开关机制

开关是在饿了么实践经验里建议降级方案,通过向后端请求一个是还是不是降级的接口,若是降级则废除掉已经登记的service Worker。那里要小心不要缓存那个开关请求。为了便利难题排查,能够设置1个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地图