通过importScripts在Service Worker中引入的脚本如何进行刷新?

9

我有一个网站,其中有一个服务工作者,如下所示:

// Import a script from another domain
importScripts('https://example.com/script.js')

假设script.js更新了一些新代码,且服务工作者由于推送事件而被激活(用户同时没有再次访问我的网站)。
每次服务工作者被激活时,importScripts是否会检查更新或者只在服务工作者第一次安装时下载script.js
有没有办法使服务工作者代码(特别是导入的脚本)在每次接收到推送消息时都刷新?

我写了一篇带有一些技巧的博客文章 - collimarco
3个回答

5
Service Workers specification中导入的脚本通过importScripts导入,并在安装/更新服务工作者时存储在映射中,然后重复使用,直到进行新的更新。这里有一个GitHub上的讨论,提供了更多细节。
我无法想象一种重新加载导入脚本的方法,当服务工作者接收到推送消息时。你的用例是什么?

很遗憾,无法更新导入的脚本。唯一的解决方法是向主服务工作者代码添加虚拟内容。这是使用案例。 - collimarco
是的,但即使如此,您也无法在推送消息到达时强制更新它,对吗? 一种较少丑陋的解决方法是使用“importedScriptName-”+导入脚本内容的哈希值+“.js”作为导入脚本的名称。这样,当导入的脚本发生更改时,服务工作者的内容也会更改。 - Marco Castelluccio
哦,你的客户编写了服务工作者,我以为它是类似于其他服务(如OneSignal)的解决方案,其中你提供服务工作者。顺便说一下,我在博客上回复了。虚拟内容解决方案需要人们知道导入脚本何时更改(因为当内容更改时,他们需要添加虚拟内容),不是吗?哈希解决方案则是自动的。生成是在服务器端完成的,因此它们属于不同的域也没有关系。 - Marco Castelluccio
据我所记,使用OneSignal时,他们编写服务工作者,而客户端不编写(这与您的情况不同)。请注意,我并不是说哈希解决方案很棒,我是说它比添加虚拟内容要好。 - Marco Castelluccio
不,这和我的情况没有区别。对于这一方面,OneSignal的行为与Pushpad完全相同。 - collimarco
显示剩余2条评论

4

通过动态生成服务工作器URL,可以强制浏览器重新验证/检查通过importScripts()包含的代码是否已更新——如果这个URL每小时更改一次,那么浏览器将下载并安装一个“新”的服务工作器,包括所有导入的脚本。

以下代码将使浏览器每小时检查依赖项:

const MAXAGE = 3600; // seconds until recheck
const URL = `/sw.js?q=${Math.floor(Date.now() / (MAXAGE * 1000))}`;
navigator.serviceWorker.register(URL);

演示 — 打开JS控制台并点击,您应该可以看到导入的脚本每10秒重新加载一次。

(这并不能完全解决您的问题(服务工作者只有在用户访问页面时才会更新,而不是在接收到推送通知时),但可能已经足够了。)


如何部署更新到服务工作者的更全面的答案:https://dev59.com/dKDia4cB1Zd3GeqPMv4F#43471531 - mjs
这在Chrome 71+上已经不再适用:https://www.chromestatus.com/feature/5748516353736704。 - ofavre

1
从Chrome 68开始,可以在注册Service Worker时设置{updateViaCache: 'none'}来实现此操作。它不会使用导入文件内容的缓存。
有关定义的完整参考,请参阅w3Chrome Updates

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接