Closed easonyq closed 5 years ago
当时直接 skipWaiting
是为了方便,大部分情况下直接 skipWaiting
是没有问题的,如果改成默认不 skipWaiting
,也可以,但是这个弹出让用户点击刷新就没有必要了
现在就有啊,一个黑色的条带个按钮,提示用户刷新。只是现在点击后单纯只刷新,因为 skipWaiting
在 SW 刚进去就执行了。
哦,你指的是那个 banner,那就是直接把原来的 skipWaiting 去掉,再加一个 updatefound
改动主要是 2 点:
core/service-worker.js
去掉 skipWaiting
,改到点击那个 banner 的处理函数里面,通过和 SW postMessage
,让 SW 接到消息,然后 skipWaiting
onupdatefound
之外,再加上 reg.waiting
的判断,也发 sw.update
事件不过我还得测测看这样是不是真的更好一些,毕竟上面的优化点仅从理论出发,还没实践过。
lavas-core-vue@1.2.3 已经发版,应用了这个改动。
对于已经通过 lavas init
项目的开发者来说,如果想体验更加完备的 SW 更新机制,除了升级自身依赖的 lavas-core-vue 版本之外,还可以根据这个 PR 对模板进行少量修改。修改主要集中于两个文件:
components/UpdateToast.vue
在 mounted()
生命周期中添加 navigator.serviceWorker.addEventListener('controllerchange', this.handleSWChange)
,在监听到控制页面的 SW 发生变化时,通知 SW 更新页面。
在 beforeDestroy()
生命周期中添加和上述代码对应的解绑代码
在 methods
中定义 handleSWChange()
,负责调用 window.location.reload()
刷新当前页面
在 handleRefresh()
中不再直接刷新页面,而是使用 postMessage
向 Service Worker 发送消息,通知其执行 skipWaiting()
core/service-worker.js
去掉 workbox.skipWaiting()
的调用,不直接执行。
接受 message
,执行 self.skipWaiting()
如果开发者没有对本地已有的 Lavas 项目的这两个文件进行过修改(可能性很高),也可以直接使用 GitHub 中的代码覆盖,省去了逐行修改的繁琐。链接在 components/UpdateToast.vue 和 core/service-worker.js
serviceWorkerRegistration.update()
能代替 self.skipWaiting()
吗?
最近在 @xiaoiver 同学的指引下,我看了两篇文章,分别是一个 Issue 和 Google 的一篇关于 Service Worker 比较新的科普文章,这两篇文章中提到了关于 SW 更新的问题,让我觉得 Lavas 对于这块的处理依然有改进之处。
简单来说,有 2 个点值得改进:
skipWaiting 不应该直接调用
目前的 Lavas 在 Service Worker 的模板
core/service-worker.js
中直接调用了workbox.skipWaiting();
,这句的作用是当有新旧两个版本的 SW 时,新的版本直接接管页面。也就是说,一旦运行注册 SW 的代码,就立马接管页面。而如果不写这句话,则表示等旧的 SW 接管的页面 全部关闭 后,再由新的 SW 接管。先说在 SW 中直接调用
skipWaiting
的问题:我们假设有 SWA 和 SWB 两个版本的 SW (同一个地址,修改后导致了两个版本)。当访问页面时,初期的请求全都经过旧版本 SWA 的处理。因为注册 SW 是个异步过程,等浏览器发现了新版本的 SWB,注册完成后,后续的页面请求都经过 SWB。这就导致了同一个页面前后经过两个 SW,就有存在问题的风险。
那应该在什么时候调用
skipWaiting
呢?正确的做法应该是在浏览器发现更新后,给用户弹出提示。然后用户点击重新加载时,一方面刷新页面 (location.reload()
),一方面让新的 SW 接管页面 (skipWaiting
)。如何检测 SW 的更新
目前 Lavas 中检测 SW 的更新用的是
registration.onupdatefound
方法。这个方法在大部分情况下运行正常,即进入页面,浏览器发现 SW 内容变化,就会触发,我们就会弹出提示。但问题出在如果用户不点我们的提示,而是直接刷新页面,情况就会超出预期。
刷新页面时,旧的页面并不直接销毁,而是要等到新的页面完成之后。这就表示,新旧两个页面是顺滑过渡的,因此 旧的 SW 接管的页面并不算关闭,从而新的 SW 也没机会接管了(因为用户没点我们的提示而是直接刷了页面,因此相当于没有调用
skipWaiting
)。这样新的 SW 会一直等待,而浏览器也不会再触发updatefound
事件,因为它刚才发过了。为了弥补这个问题,需要在注册 SW 时判断这个 SW 是不是处于等待状态?如果是,则表示也应该弹出提示,引导用户点击提示,最重要的是执行
skipWaiting
。这个改动在这个 PR 中有提及。具体到 Lavas 中,主要是注册模板的修改。在获得
reg
对象后,还需判断reg.waiting
。如果是的话,也要触发sw.update
事件。我会在最近进行这两处修改