【问题标题】:Prevent Service Worker from automatically stopping防止 Service Worker 自动停止
【发布时间】:2025-12-16 06:20:02
【问题描述】:

Service Worker 似乎会在某个时候自动停止。此行为无意中关闭了在激活时建立的 WebSocket 连接。

何时以及为何停止?如何以编程方式禁用此意外操作以保持 Service Worker 继续运行?

【问题讨论】:

  • 出于好奇,您为什么不为此使用 SharedWorkers?
  • @JaffaTheCake 仅仅因为 ServiceWorker 对于我的小型离线应用程序来说足够复杂。我曾经实现 SharedWorker + Appcache 方法,但由于 更长的寿命 的东西,我切换到了 ServiceWorker。此外,SharedWorker 在重新加载页面上有a bug

标签: javascript service-worker


【解决方案1】:

您看到的是预期的行为,而且不太可能改变。

Service Worker 的寿命故意很短。他们为响应特定事件而“出生”(installactivatemessagefetchpush 等),执行任务,然后不久之后“死亡”。生命周期通常足够长,以至于在工人死亡之前可能会处理多个事件(即install 后面可能跟着activate 后面跟着fetch),但它最终会死亡。这就是为什么不要依赖脚本中的任何全局状态以及在服务工作者启动时通过 IndexedDB 或缓存存储 API 引导所需的任何状态信息非常重要的原因。

Service Worker 是在您访问特定网页时安装的有效后台进程。如果允许这些后台进程无限期运行,则会增加对设备/计算机的电池和性能产生负面影响的风险。为了降低这种风险,您的浏览器只会在它知道有必要时运行这些进程,即响应事件。

WebSockets 的一个用例是让您的客户端监听来自服务器的一些数据。对于该用例,使用WebSockets 的服务工作者友好替代方案是使用Push Messaging API 并让您的服务工作者响应push 事件。请注意,在当前的 Chrome 实现中,您必须在处理 push 事件时显示用户可见的通知。目前不支持“静默”push 用例。

如果您不使用来自服务器的数据,而是使用WebSockets 作为将数据从客户端发送到服务器的一种方式,那么不幸的是,没有很好的服务工作者友好的方式来做到这一点。在未来的某个时候,可能有一种方法可以注册您的服务工作者,以便通过基于周期性/时间的事件唤醒您,此时您可以使用fetch() 将数据发送到服务器,但目前不支持在任何浏览器中。

P.S.:Chrome(通常)在您打开 DevTools 界面时不会杀死服务工作者,但这只是为了简化调试,而不是您应该依赖于真实应用程序的行为。

【讨论】:

  • 这对我来说是一个非常非常糟糕的消息。从您的角度来看,与 SharedWorker 相比,ServiceWorker 实际上只是存在时间更长,但寿命短暂,而不是更长的寿命。恕我直言,至少在所有相关页面关闭之前它应该是活动的(如 SharedWorker)。我曾经很喜欢ServiceWorker,但现在我的心因此彻底碎了。
  • ServiceWorker 用于处理需要在页面上下文之外触发的事件。它不用于后台处理,这就是 SharedWorker 的用途。如果您尝试使用它进行处理,它可能会阻止 fetch 事件,这对性能来说很糟糕。我们希望在 inside ServiceWorkers 中启用 SharedWorkers,因为它们用于不同的事情。
  • 我认为 PWA 在哪里可以击败原生应用程序,目前阻碍我们的是:长时间运行的后台任务,我们在网络中永远无法拥有的原始 tcp 和 udp 东西? 我宁愿想要拥有一些允许长时间运行 sw 的权限 api 或查看浏览器通知执行负面的工作人员。长期运行的服务人员也有良好的意图。一个简单的提示“example.com 仍在运行后台处理...[destroy][keep alive][ ] 不要再问”会让我开心
  • @JaffaTheCake ...这意味着我不应该使用服务工作者来与多个页面共享 WebSocket 连接并使其保持活动状态。谢谢你的话。
  • 差不多 6 年后的 “在未来的某个时候,可能有一种方法可以让你的服务人员通过周期性/基于时间的事件被唤醒 […]” 对这个显然非常需要的功能有什么计划吗?
【解决方案2】:

理论

Jeff's answer explains 理论部分 - 为什么和如何,详细。

它还包含许多关于您可能不想追求这一点的好处。

但是,在我的情况下,缺点是不存在的,因为我的应用程序将在桌面计算机上运行,​​而这些计算机仅用于运行我的应用程序。但是即使浏览器窗口被最小化,我也需要保持 SW 活着。因此,如果您正在开发将在各种设备上运行的 Web 应用程序,那么对于上述答案中讨论的事情,保持 SW 活动可能不是一个好主意。

话虽如此,让我们转向实际的实际答案。

我的“实用”解决方案

应该有很多方法可以让 SW 保持活力,因为 SW 在响应许多不同的事件后会保持活力。就我而言,我将一个虚拟文件放到服务器上,将其缓存在 SW 中,并定期从 document 请求该文件。

因此步骤是;

  • 在服务器上创建一个虚拟文件,比如ping.txt
  • 在您的软件上缓存文件
  • 定期从您的 html 请求该文件以保持 SW 活动

示例

// in index.html
setInterval(function(){
    fetch('/ping.txt')
}, 20000)

请求不会真正到达服务器,因为它会被缓存在 SW 上。尽管如此,这将使 SW 保持活动状态,因为它会响应 fetch 甚至是由请求引起的。

PS:我发现 20 秒是保持 SW 活跃的一个很好的时间间隔,但它可能会改变你,你应该尝试看看。

【讨论】:

  • 这只会在选项卡打开时保持活动状态。浏览器关闭后如何使其保持活跃?
  • @CoreyAlix 我认为这是不可能的。但我很想知道你是否以某种方式做到了这一点。