我也曾经难以理解Clients.claim的作用,看过很多解释都不够清晰明了。希望我的回答能够帮助到跟我一样困惑的人。
要理解Clients.claim,我们需要了解service worker的生命周期:
- 安装阶段:注册后的第一阶段。当
oninstall
处理程序完成时,服务 worker 被视为已安装。
- 已安装阶段:等待使用其他服务 worker 的客户端。
- 激活阶段:没有被其他服务 worker 控制的客户端。当
onactivate
处理程序完成时,服务 worker 被视为已激活。
- 已激活阶段:服务 worker 现在控制着页面。
skipWaiting 和 Clients.claim 解决的是不同的问题。
Clients.claim 仅对于网页从未被 service worker 控制变为被控制的情况有影响。
skipWaiting 正如它所说的那样,它跳过等待阶段并直接进入激活状态。一旦激活,它就是所有客户端的活动服务 worker,其中客户端是指在您的 service worker 范围内打开网页的任何窗口或选项卡。
那么我们为什么还需要Clients.claim呢?
这也曾经让我困惑,可能你也是。最好通过一个例子来说明回答。
假设您的网页尚未注册服务 worker,因此未被控制。您有两个标签页(客户端)打开了您的网页。您更新网页以便注册服务 worker。
你决定重新加载第一个选项卡(客户端),它现在会获取注册服务 worker 的脚本并开始安装。安装完成后,它会注意到没有其他客户端正在被服务 worker 控制,因此不必等待,可以立即安全地激活服务 worker,并且任何资源的获取现在都将通过您的服务 worker 进行。
然而,这里有个问题,另一个标签页(客户端)现在也有了一个活动的服务 worker,但是它还没有被控制。这意味着任何获取都不会通过服务 worker 进行。您需要重新加载任何其他标签页(客户端)才能使其被活动服务 worker 控制。这很令人困惑,因为如果以后任何新的服务 worker 通过强制使用skipWaiting而变为活动状态,则其他标签页(客户端)将立即由新的活动服务 worker 控制。因此我强调重新加载部分仅在未被控制的网页变为受控制时需要。
这时就需要Clients.claim了。当您在第一个服务 worker 激活时调用 self.clients.claim(),像这样:
self.addEventListener('activate', event => {
event.waitUntil(clients.claim());
});
它将确保其他未受控制但具有活动服务工作者的选项卡(客户端)由活动服务工作者控制。这意味着对于任何资源的提取现在都会通过活动服务工作者进行。如果没有Clients.claim,则服务工作者直到重新加载页面才被使用。
同样,如果所有网页已由服务工作者控制。 如果检测到并安装了一个新的服务工作者,则通常等待关闭包含该网页(客户端)的所有选项卡。下次访问该网页时,将激活新的服务工作者并由其控制该网页。
但是,如果您不关闭所有客户端,并使用skipWaiting强制使用新的服务工作者,它将立即对所有客户端进行激活和控制。这意味着来自任何客户端的任何新提取都将立即通过您的新服务工作者进行。现在,您无需使用Clients.claim即可使其他客户端开始使用新的服务工作者。
这是我的尝试,希望能帮助到某些人。
registration.update()
并不是为了检查是否有更新的服务工作者脚本而必需的。在导航请求后,浏览器已经自动完成了此操作。registration.update()
允许您在不必等待导航请求的情况下进行检查,但通常是不必要的。 - Jeff Posnick