现在很流行基于Github page和markdown的静态blog,非常适合技术的思维和习惯,针对不同的语言都有一些优秀的静态blog系统出现,如Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于静态内容的特性非常适合做缓存来加速页面的访问,就利用Service worker来实现加速,结果是除了PageSpeed,CDN这些常见的服务器和网络加速之外,通过客户端实现了更好的访问体验。
加速/离线访问只需三步
- 首页添加注册代码
|
|
- 复制代码
将https://alphayang.github.io/sw.js保存到你的网站根目录下
- 修改不缓存域名列表及离线状态页面
在你的sw.js中修改
打开Chrome Dev Tools->Source
,看看自己的blog都引用了哪些第三方资源,逐个加到忽略列表里。
在根目录下添加offline.html,在没有网络且缓存中也没有时使用,效果如下:
在根目录下添加offline.svg,在无网络时图片资源请求返回该文件。
加速效果
首页加速后,网络请求从16降为1,加载时间从2.296s降为0.654s,得到了瞬间加载的结果。
查看测试结果
加速/离线原理探索
什么是 Service worker
如上图,Service worker 是一种由Javascript编写的浏览器端代理脚本,位于你的浏览器和服务器之间。当一个页面注册了一个 Service worker,它就可以注册一系列事件处理器来响应如网络请求和消息推送这些事件。Service worker 可以被用来管理缓存,当响应一个网络请求时可以配置为返回缓存还是从网络获取。由于Service worker 是基于事件的,所以它只在处理这些事件的时候被调入内存,不用担心常驻内存占用资源导致系统变慢。
Service worker生命周期
Service worker 为网页添加一个类似于APP的生命周期,它只会响应系统事件,就算浏览器关闭时操作系统也可以唤醒Service worker,这点非常重要,让web app与native app的能力变得类似了。
Service worker在Register时会触发Install事件,在Install时可以用来预先获取和缓存应用所需的资源并设置每个文件的缓存策略。
一旦Service worker处于activated状态,就可以完全控制应用的资源,对网络请求进行检查,修改网络请求,从网络上获取并返回内容或是返回由已安装的Service worker预告获取并缓存好的资源,甚至还可以生成内容并返回给网络语法。
所有的这些都用户都是透明的,事实上,一个设计优秀的Service worker就像一个智能缓存系统,加强了网络和缓存功能,选择最优方式来响应网络请求,让应用更加稳定的运行,就算没有网络也没关系,因为你可以完全控制网络响应。
Service worker的控制从第二次页面访问开始
在首次加载页面时,所有资源都是从网络载的,Service worker 在首次加载时不会获取控制网络响应,它只会在后续访问页面时起作用。
页面首次加载时完成install,并进入idle状态。
页面第二次加载时,进入activated状态,准备处理所有的事件,同时 浏览器会向服务器发送一个异步 请求来检查Service worker本身是否有新的版本,构成了Service worker的更新机制。
当Service worker处理完所有的事件后,进入idle状态,最终进入terminated状态资源被释放,当有新的事件发生时再度被调用。
特点
- 浏览器
Google Chrome,Firefox,Opera以及国内的各种双核浏览器都支持,但是 safari 不支持,那么在不支持的浏览器里Service worker不工作。
- https
网站必须启用https来保证使用Service worker页面的安全性,开发时localhost默认认为是安全的。
- non-block
Service worker 中的 Javascript 代码必须是非阻塞的,因为 localStorage 是阻塞性,所以不应该在 Service Worker 代码中使用 localStorage。
- 单独的执行环境
Service worker运行在自己的全局环境中,通常也运行在自己单独的线程中。
- 没有绑定到特定页面
service work能控制它所加载的整个范围内的资源。
- 不能操作DOM
跟DOM所处的环境是相互隔离的。
- 没有浏览页面时也可以运行
接收系统事件,后台运行
- 事件驱动,需要时运行,不需要时就终止
按需执行,只在需要时加载到内存
- 可升级
执行时会异步获取最新的版本
实现加速/离线
Cache
网页缓存有很多,如HTTP缓存,localStorage,sessionStorage和cacheStorage都可以灵活搭配进行缓存,但操作太繁琐,直接使用更高级Service worker –本文的主人公。
添加Service worker入口
在web app的首页添加以下代码
如果浏览器支持serviceWorker就注册它,不支持还是正常浏览,没有Service worker所提供的增强功能。
Service worker控制范围:
简单情况下,将sw.js
放在网站的根目录下,这样Service worker可以控制网站所有的页面,,同理,如果把sw.js
放在/my-app/sw.js
那么它只能控制my-app
目录下的页面。
把sw.js
放在/js/
目录呢?更好的目录结构和范围控制呢?
在注册时指定js位置并设置范围。
Service worker实现
监听三个事件:
install
|
|
install时将所有符合缓存策略的资源进行缓存。
fetch
|
|
activate
|
|
在activate时根据version值来删除过期的缓存。
管理 Service worker
特定网站
- Google Chrome
Developer Tools
->Application
->Service Workers
,
在这里还有三个非常有用的复选框:
- Offline
模拟断网状态
Update on reload
加载时更新Bypass for network
总是使用网络内容
- Firefox
只有在Settings里有一个可以在HTTP环境中使用Service worker的选项,适应于调试,没有单独网站下的Service worker管理。
- Opera及其它双核浏览器同Google Chrome
如果看到多个相同范围内的多个Service worker,说明Service woker更新后,而原有Service worker还没有被terminated。
浏览器全局
看看你的浏览器里都有哪些Service worker已经存在了
- Google Chrome
在地址栏里输入:
可以看到已经有24个Service worker了,在这里可以手动Start让它工作,也可以Unregister卸载掉。
- Firefox
有两种方式进入Service worker管理界面来手动Start或unregister。
菜单栏,Tool->Web Developer->Service workers
地址栏中输入
|
|
- Opera及其它双核浏览器同Google Chrome
更多
TODO:
Service workers的更新需要手动编辑version,每次发布新文章时需要编辑。
使用AMP让页面渲染速度达到最高。
Ref links
Chrome service worker status page
Firefox service worker status page