在前端 越来越重 的这个时代,页面加载速度 成为了一个重要的 指标。对于这个问题,业界也有一些解决方案。
- 浏览器缓存、协议缓存、强缓存
- 懒加载(首屏)
- CDN 多域名突破下载并发限制。
其实在两年前内部就对这块内容做过调研了。appCache
方案?PWA
方案?但是 最后都没选择 。
之前看代码,发现是 localstroage
存代码,如果有就拿 localstroage
去用。省去了这一部分加载的时间。
上个同事离职了。当时的调研结果我也忘了。只能再开始新一轮的调研,我选择的是 PWA
方案。(如果说是网速拖慢了加载速度,那么我的网页可以离线访问不就速度起飞了?)
网上的资料很少。我希望我可以写一篇帮助下一个想使用 PWA
方案的人。
Service Workers
Service worker
是一个注册在 指定源和路径 下的事件驱动worker
。
Service worker
运行在 worker
上下文,因此它 不能访问 DOM。不同于主线程,它运行在其他线程中,所以 不会造成主线程阻塞。它设计为 完全异步,同步 API(如 XHR 和 localStorage)不能在 s ervice worker 中使用。
Service workers
本质上充当 Web 应用程序(服务端) 与浏览器 (客户端) 之间的 代理服务器 。
可以提供有效有效的离线体验,拦截网络请求。还可以推送通知。
Service Workers 需要注意的地方
-
需要支持 HTTPS 访问你的页面。出于安全原因,
Service Workers
要求必须在HTTPS
下才能运行。(其实好多API
都需要HTTPS
的支持) - 资源路径为 根目录的绝对路径 。最大作用域 (
scope
),为资源路径。https://www.lilnong.top/static/js/sw-20190621.js
的最大作用路径为/static/js/
- 为了便于本地开发,
localhost
也被浏览器认为是安全源。 - 在已经支持
serivce workers
的浏览器的版本中,很多特性没有默认开启。如果你发现示例代码在当前版本的浏览器中怎么样都无法正常运行,你可能需要开启一下浏览器的相关配置:
Firefox Nightly: 访问about:config
并设置dom.serviceWorkers.enabled
的值为true
; 重启浏览器;
Chrome Canary: 访问chrome://flags
并开启experimental-web-platform-features;
重启浏览器 (注意:有些特性在Chrome
中没有默认开放支持);
Opera: 访问opera://flags
并开启ServiceWorker
的支持; 重启浏览器。
service worker 声明周期
-
下载
- 首次访问
service worker
控制的网站或页面时,service worker
会立刻被下载。 - 至少每 24 小时它会被下载一次。
- 首次访问
-
安装
- 首次下载会尝试安装,
- 下载的文件是新的,尝试进行安装
-
激活
- 安装成功后它会被激活
- 如果现有
service worker
已启用,新版本会在后台安装,但不会被激活,这个时序称为worker in waiting
- 直到所有已加载的页面不再使用旧的
service worker
才会激活新的service worker
。新的service worker
会被激活(成为active worker
)。
我们页面引入 sw.js
内容为 a
。当我们修改为b
。
这时候 a
和b
都是已经安装完毕的,但是 a
是当前正在用的。b
需要等没有页面在用a
,才会进入激活状态。
Cache
Cache
为缓存的 Request
/Response
对象对提供存储机制。
当前我们作为 ServiceWorker
生命周期的一部分。尽管它被定义在 service worker
的标准中, 但是它不必一定要配合 service worker
使用。也暴露在 window
作用域下的。
- Cache.add(request)
request
是一个字符串类型的URL
。如cache.add('https://www.lilnong.top/static/css/normalize-8.0.0.css')
功能上等于调用fetch()
, 然后使用Cache.put()
将response
添加到cache
中。 - Cache.addAll(requests)
功能同上,只不过入参为 字符串数组 -
Cache.match(request, options)
返回一个Promise
对象,resolve
的结果是跟Cache
对象匹配已经缓存的请求。requres
同上,是要匹配的URL
options
如下-
ignoreSearch
: 设置是否忽略url
中的query
。该选项默认为false
。 -
ignoreMethod
:true
匹配时就不会验证Request
对象的http
方法 (通常只允许是GET
或HEAD
。) 该参数默认值为 false。 -
ignoreVary
: 为 true 时匹配不进行VARY
部分的匹配。例如,如果一个URL
匹配,此时无论Response
对象是否包含VARY
头部,都会认为是成功匹配。该参数默认为 false。 -
cacheName
: 一个 DOMString,代表一个具体的要被搜索的缓存。注意该选项被 Cache.match()方法忽略。
-
- Cache.matchAll(request, options)
同上 ,返回一个 Promise 对象,resolve 的结果是跟 Cache 对象匹配的 所有请求组成的数组。 - Cache.put(request, response)
人为的,为一个URL
设置response
- Cache.delete(request, options)
搜索条目。如果找到,则删除该Cache
条目,并且返回一个resolve
为true
的Promise
对象;如果未找到,则返回一个resolve
为false
的Promise
对象。 - Cache.keys(request, options)
返回一个 Promise 对象,resolve
的结果是Cache
对象key
值(request 对象)组成的数组。
ServiceWorker 的使用
-
serviceWorkerContainer.register()
来注册 - 注册成功的话,会开启 另一个线程 来做这件事。与我们的网页是 互不相干 的。
-
service worker
现在可以接收事件。 -
service worker
控制的页面打开后会尝试去安装service worker
。 - 最先发送给
service worker
的事件是安装事件(在这个事件里可以开始进行填充 IndexDB 和缓存站点资源),让所有资源可离线访问。 - 当
oninstall
事件的处理程序执行完毕后,可以认为service worker
安装完成了。 - 当
service worker
安装完成后,会接收到一个激活事件onactivate
主要用途是清理先前版本的service worker
脚本中使用的资源。 -
Service Worker
现在可以控制页面了,但仅是在register()
成功后的打开的页面。
ServiceWorker 的注册
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/'}).then(function(reg) {
// registration worked
console.log('Registration succeeded. Scope is' + reg.scope);
}).catch(function(error) {
// registration failed
console.log('Registration failed with' + error);
});
}
微信公众号
总结
测试路径
https://www.lilnong.top/stati…
https
-
SW
通过fetch
来实现代理浏览器请求。 -
SW
注册之后会尝试安装。但是激活需要等下次(没有再用的资源了) -
SW
要注意他限制的域 -
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
是一个封装包 -
vue-cli
也有一些webpack
支持的工具@vue/pwa
@vue/cli-plugin-pwa
资料
- Service_Worker_API –mdn
- Service Workers –mdn
- cache –mdn
-
AppCache –mdn
这个内容我觉得不用再关心了<html manifest="example.appcache">
- 前端每周清单半年盘点之 PWA 篇 — 王下邀月熊_Chevalier
- 傻傻分不清的 Manifest
- PWA 之 workbox 学习
- 初探 PWA