博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Workbox3 - ServiceWorker可以如此简单
阅读量:6585 次
发布时间:2019-06-24

本文共 3698 字,大约阅读时间需要 12 分钟。

如果你追求极致的WEB体验,你一定在站点中使用过PWA,也一定面临过在编写serviceWorker代码时的犹豫不决,因为serviceWorker太重要了,一旦注册在用户的浏览器,全站的请求都会被serviceWorker控制,一不留神,小问题也成了大问题了。不过到了现在有了Workbox 3,一切关于serviceWorker都不再是问题。

科普ServiceWorker

如果你已经熟悉ServiceWorker,可以跳过此段。

ServiceWorker是PWA中最重要的一部分,它是一个网站安插在用户浏览器中的大脑。ServiceWorker是这样被注册在页面上的

if ('serviceWorker' in navigator) {  navigator.serviceWorker.register('/sw.js')}复制代码

为什么说SW(下文将ServiceWorker简称为SW)是网站的大脑?举个例子,如果在www.example.com的根路径下注册了一个SW,那么这个SW将可以控制所有该浏览器向www.example.com站点发起的请求。只需要监听fetch事件,你就可以任意的操纵请求,可以返回从cacheStorage中读的数据,也可以通过fetch API发起新的请求,甚至可以new一个Response,返回给页面。

// 一段糟糕的sw代码,在这个SW注册好以后,整个SW控制站点的所有请求返回的都将是字符串"bad",包括页面的HTMLself.addEventListener('fetch', function(event) {  event.respondWith(    new Response('bad')  );});复制代码

就是因为SW权利太大了,写起来才会如履薄冰,一不小心有些页面资源就不能及时正确的更新了。

一个还算完整ServiceWorker

先来看一个直接手写的SW文件

var cacheStorageKey = 'cachesName'var cacheList = [  // 注册成功后要立即缓存的资源列表]// 当浏览器解析完sw文件时触发install事件self.addEventListener('install', function(e) {  // install事件中一般会将cacheList中要换存的内容通过addAll方法,拉一遍放入caches中  e.waitUntil(    caches.open(cacheStorageKey).then(function(cache) {      return cache.addAll(cacheList)    })  )})// 激活时触发activate事件self.addEventListener('activate', function(e) {  // active事件中通常做一些过期资源释放的工作,匹配到就从caches中删除  var cacheDeletePromises = caches.keys().then(cacheNames => {    return Promise.all(cacheNames.map(name => {      if (name !== cacheStorageKey) {        return caches.delete(name);      } else {        return Promise.resolve();      }    }));  });  e.waitUntil(    Promise.all([cacheDeletePromises])  )})self.addEventListener('fetch', function(e) {  // 在此编写缓存策略  e.respondWith(    // 可以通过匹配缓存中的资源返回    caches.match(e.request)    // 也可以从远端拉取    fetch(e.request.url)    // 也可以自己造    new Response('自己造')    // 也可以通过吧fetch拿到的响应通过caches.put方法放进chches  )})复制代码

其实所有站点SW的install和active都差不多,无非是做预缓存资源列表,更新后缓存清理的工作,逻辑不太复杂,而重点在于fetch事件。上面的代码,我把fetch事件的逻辑省略了,因为如果认真写的话,太多了,而且也不利于讲明白缓存策略这件事。想象一下,你需要根据不同文件的扩展名把不同的资源通过不同的策略缓存在caches中,各种css,js,html,图片,都需要单独搞一套缓存策略,你就知道fetch中需要写多少东西了吧。

Workbox 3

workbox的出现就是为了解决上面的问题的,它被定义为PWA相关的工具集合,其实围绕它的还有一些列工具,如workbox-cli、gulp-workbox、webpack-workbox-plagin等等,不过他们都不是今天的重点,今天想聊的就是workbox本身。

其实可以把workbox理解为Google官方PWA框架,它解决的就是用底层API写PWA太过复杂的问题。这里说的底层API,指的就是去监听SW的install, active, fetch事件做相应逻辑处理等。使用起来是这样的

// 首先引入workbox框架importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.3.0/workbox-sw.js');workbox.precaching([  // 注册成功后要立即缓存的资源列表])// html的缓存策略workbox.routing.registerRoute(  new RegExp(''.*\.html'),  workbox.strategies.networkFirst());workbox.routing.registerRoute(  new RegExp('.*\.(?:js|css)'),  workbox.strategies.cacheFirst());workbox.routing.registerRoute(  new RegExp('https://your\.cdn\.com/'),  workbox.strategies.staleWhileRevalidate());workbox.routing.registerRoute(  new RegExp('https://your\.img\.cdn\.com/'),  workbox.strategies.cacheFirst({    cacheName: 'example:img'  }));复制代码

上面的代码理解起来就容易的多了,通过workbox.precaching中的是install以后要塞进caches中的内容,workbox.routing.registerRoute中第一个参数是一个正则,匹配经过fetch事件的所有请求,如果匹配上了,就走相应的缓存策略workbox.strategies对象为我们提供了几种最常用的策略,如下

Stale-While-Revalidate

Cache First

Network First

1

Network Only

1

Cache Only

1

你可以通过plagin扩展这些策略,比如增加个缓存过期时间(官方有提供)什么的。甚至可以继续监听fetch事件,然后使用这些策略,官方文档在.

经验之谈

在经过一段时间的使用和思考以后,给出我认为最为合理,最为保守的缓存策略。

HTML,如果你想让页面离线可以访问,使用NetworkFirst,如果不需要离线访问,使用NetworkOnly,其他策略均不建议对HTML使用。

CSS和JS,情况比较复杂,因为一般站点的CSS,JS都在CDN上,SW并没有办法判断从CDN上请求下来的资源是否正确(HTTP 200),如果缓存了失败的结果,问题就大了。这种我建议使用Stale-While-Revalidate策略,既保证了页面速度,即便失败,用户刷新一下就更新了。

如果你的CSS, JS与站点在同一个域下,并且文件名中带了Hash版本号,那可以直接使用Cache First策略。

图片建议使用Cache First,并设置一定的失效事件,请求一次就不会再变动了。

上面这些只是普适性的策略,见仁见智。

还有,要牢记,对于不在同一域下的任何资源,绝对不能使用Cache only和Cache first。

参考文献

原文发布时间为:2018年06月30日

作者:GeoffZhu

本文来源:如需转载请联系原作者

你可能感兴趣的文章
sed 详解
查看>>
jQ插件--时间线插件和拖拽API
查看>>
python第三方库系列之十九--python測试使用的mock库
查看>>
浏览器渲染模式设置
查看>>
atitit.userService 用户系统设计 v4 q316 .doc
查看>>
html中offsetTop、clientTop、scrollTop、offsetTop各属性
查看>>
HDU 5715 XOR 游戏 二分+字典树
查看>>
使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(四)-- Middleware
查看>>
[C#] 走进异步编程的世界 - 在 GUI 中执行异步操作
查看>>
Atitit html5 Canvas 如何自适应屏幕大小
查看>>
Javascript的setTimeOut()和setInterval()的定时器用法
查看>>
request.getSession()几种获取情况之间的差异
查看>>
PayPal加密证书.pem的生成
查看>>
Unity官方发布热更新方案性能对照
查看>>
序列化与反序列化
查看>>
正态分布及标准化
查看>>
既使用maven编译,又使用lib下的Jar包
查看>>
【转】浅谈php://filter的妙用
查看>>
leetcode344 反转字符串 c++实现
查看>>
【转】网络字节序与主机字节序
查看>>