ServiceWorker 更新方案

目录

  • 为什么加 serviceWorker 缓存

  • 加缓存后引发的问题

  • 探索强制更新方案

  • 实现细节

为什么加 serviceWorker 缓存

serviceWorker 具体用法可参考文章 [serviceWorker 实战]

下面通过几张图的对比来看下加缓存后的具体效果:

深圳请求广州服务器,请求距离近,不加缓存 51ms

深圳请求广州服务器,请求距离近,加缓存后 27ms

深圳请求南京服务器,请求距离远,不加缓存 106ms

深圳请求南京服务器,请求距离远,加缓存后 44ms

用 3G 网络,不加缓存 594ms

用 3G 网络,加缓存后 26ms

对比后发现:

  1. 不加缓存:html 请求时间,与服务器距离和网速有关,距离越远、网络越差耗时越多,在 50ms~600ms+

  2. 加缓存:html 请求时间,与服务器距离和网速有无关,稳定在 50ms 以内

结论:

加 serviceWorker 缓存可确保各地用户在网络不好的时候都能快速拿到 html

加缓存后引发的问题

缓存更新策略:

用户进入网页,没有缓存,通过网络请求 html,拿到结果后加入缓存

用户进入网页,有缓存后,先读取缓存的 html 去渲染执行,然后请求新的 html 去更新缓存

通过下面两张图来看下 serviceWorker 具体的更新机制:

存在的问题:

用户需要进 2 次网页才能看到最新的版本功能

探索强制更新方案

如何实现按需更新网页?探索了以下几个方案:

方案1-文件变更

最开始想到的方法:

发版的时候更新 serviceWorker.js 里面的版本号引起文件的变更从而使 serviceWorker 重新安装激活

执行顺序:fetch 请求 html => serviceWorker.register() => 发现变更重新安装激活

结论:方案行不通,html 的请求是最早的,而 serviceWorker 的注册、安装、激活更滞后

方案2-监听更新事件

监听 serviceWorker 的更新事件:

  1. 当 ServiceWorker installing 属性获取新的服务工作线程时,会触发 updatefound 事件

  2. 更新 serviceWorker.js 里面的版本号,引发重新安装激活,同时监听 updatefound 事件

  3. 发现有更新就出提示弹框,用户点击后,强制刷新浏览器更新

结论:方案可行,但是用户体验不好,用户需要手动点击强制刷新

方案3-自动刷页面

偷偷刷新页面:

用户进入页面后,出 loading,自动去刷新 1 次页面

可以前端自己强刷 1 次

内嵌在客户端的可以让客户端容器强刷 1 次

结论:体验不好

方案4-配置文件

在 fetch 里做拦截,比较远程配置:

fetch 拦截时机最早,拦截 html 请求的时候,先去请求1个远程配置文件

然后比较配置文件里的版本号和缓存的版本号,一致走缓存,不一致走网络请求

请求远程配置文件会有一定耗时,耗时过久会抵消缓存产生的效益

结论:方案可行,需要控制住配置文件请求耗时

方案5-URL标识

在 fetch 里做拦截,比较 url:

fetch 拦截时机最早

需要强制刷新的时候,修改访问链接 url 携带的标识字段值

fetch 拦截 html 请求的时候,通过比较 url 标识和缓存标识,一致走缓存,不一致走网络请求

需要具备变更 url 的条件(比如由内嵌容器控制入口和变更)

结论:方案可行,需要 url 具备可变更条件

实现细节

因为项目内嵌在客户端容器里,支持动态拼接修改 url,所以用的是方案5

下面看下具体实现:

实现逻辑

  1. 网站核心入口是 html,资源类型为 document

  2. 客户端控制在跳对应网站的时候,url 上拼接 readerVersion=new1

  3. serviceWorker fetch 拦截 html,判断缓存的 readerVersion 值和 url 上的值是否一致:

  • 一致,走本地缓存,同时更新 serviceWorker 的缓存

  • 不一致,走网络请求,请求成功后更新 serviceWorker 的缓存

  • 网络请求失败走 serviceWorker 的旧缓存兜底

具体操作

  1. 前端代码发布上线,此时 readerVersion => ''

  2. 配置平台修改 readerVersion => new1+

  3. 上线完毕,看数据大部分用户更新后,可恢复配置 readerVersion => '',也可不恢复

注意事项

  1. 强制更新客户端 readerVersion=new1 每次需要加 1,new1 => new2

  2. fetch 拦截 html 请求需要排除 favicon.ico,服务器会自动请求此图标链接,同样返回 html

相关推荐
qiyi.sky5 分钟前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~9 分钟前
分析JS Crash(进程崩溃)
java·前端·javascript
哪 吒11 分钟前
华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)
javascript·python·华为od
安冬的码畜日常18 分钟前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
l1x1n01 小时前
No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史
前端·http·html
Q_w77421 小时前
一个真实可用的登录界面!
javascript·mysql·php·html5·网站登录
昨天;明天。今天。1 小时前
案例-任务清单
前端·javascript·css
一丝晨光1 小时前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby
Front思1 小时前
vue使用高德地图
javascript·vue.js·ecmascript
zqx_72 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架