`self.Clients.claim()`有什么用

What is the use of `self.Clients.claim()`

注册service worker,我可以调用

navigator.serviceWorker.register('/worker.js')

每次加载页面时,它都会检查 worker.js 的更新版本。如果发现更新,则在关闭并重新打开页面的所有选项卡之前,不会使用新工作程序。我阅读的解决方案是:

self.addEventListener('install', function(event) {
  event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function(event) {
  event.waitUntil(self.clients.claim());
});

我能理解 skipWaiting 部分,但 clients.claim() 到底是做什么的?我做了一些简单的测试,即使没有它,它似乎也能按预期工作。

我从 guide to the service worker lifecycle 中摘录以下内容:

clients.claim

You can take control of uncontrolled clients by calling clients.claim() within your service worker once it's activated.

Here's a variation of the demo above which calls clients.claim() in its activate event. You should see a cat the first time. I say "should", because this is timing sensitive. You'll only see a cat if the service worker activates and clients.claim() takes effect before the image tries to load.

If you use your service worker to load pages differently than they'd load via the network, clients.claim() can be troublesome, as your service worker ends up controlling some clients that loaded without it.

Note: I see a lot of people including clients.claim() as boilerplate, but I rarely do so myself. It only really matters on the very first load, and due to progressive enhancement the page is usually working happily without service worker anyway.

Service worker 在注册后从 next page-reload 获取控制权。通过使用 self.skipWaiting()self.clients.claim(),您可以要求客户端控制 first load 本身的 service worker。

例如

假设我缓存了一个文件 hello.txt,如果我再次调用 hello.txt,即使我的缓存中有资源,它也会调用服务器。这是我不使用 self.clients.claim() 时的场景。但是,在下一页重新加载时为 hello.txt 发出服务器调用时,它将从缓存中提供资源。

为了解决这个问题,我必须结合使用 self.skipWaiting()self.clients.claim() 以便 service worker 在激活后立即开始提供内容。

P.S:

next page-reload表示页面重访。

first load表示第一次访问页面的时刻。

Clients.claim() 使服务工作者在您首次注册服务工作者时控制页面。如果页面上已经有 Service Worker,则没有任何区别。 skipWaiting() 让新的 service worker 替换旧的。如果没有它,您将不得不在激活新的 service worker 之前关闭该页面(以及任何其他打开的包含同一范围内页面的选项卡)。

我也无法理解 clients.claim 并且 none 的解释对我来说很有意义所以希望这个答案也能帮助任何挣扎的人。

要理解Clients.claim,我们必须查看 worker 生命周期。

  1. 正在安装;这是注册后的第一阶段。当 oninstall 处理程序完成时,服务工作者被认为已安装。
  2. 已安装; Service Worker 正在等待使用其他 Service Worker 的客户端关闭。
  3. 正在激活;没有其他服务人员控制的客户。当 onactive 处理程序完成时,service worker 被认为已激活。
  4. 已激活; Service Worker 现在控制页面。

skipWaitingClients.claim是为了解决不同的问题而设计的

Clients.claim ONLY 对您的网页第一次从不受控制的网页变为受控制的 (通过服务工作者)网页通过注册服务工作者。

skipWaiting 正是它所说的。它跳过等待阶段,直接进入激活阶段。一旦激活,它现在是所有客户端的活动服务工作者。客户端是任何 window 或在您的服务人员范围内打开网页的选项卡。


那么为什么我们需要Clients.claim呢?

这让我很困惑,我敢打赌它也让你很困惑。最好在示例中描述答案。

假设您的网页没有注册服务人员,因此不受控制。您打开了网页的两个选项卡(客户端)。您对您的网页进行了更新,以便它现在可以注册一个 service worker。

您决定重新加载第一个选项卡(客户端),它现在将获取注册服务工作者的脚本并开始安装。安装后,它会注意到没有其他客户端被 service worker 控制,因此它不必等待,它可以立即安全地激活 service worker,任何资源的获取现在都将通过您的 service worker。

然而,这里有一个问题,你的另一个选项卡(客户端)现在也将有一个活跃的服务工作者,但是,它还没有被控制。这意味着任何获取都不会通过 service worker。您需要重新加载任何其他选项卡(客户端),以便它由活动的服务工作者控制。这是令人困惑的,因为如果此后任何新的服务工作者通过 skipWaiting 强制激活它,其他选项卡(客户端)将立即由新的活动服务工作者控制。所以我强调重新加载部分是需要的 ONLY 当不受控制的网页变得受控时。

输入Clients.claim。当你在第一个 service worker 中调用 self.clients.claim() 时,它会被激活,就像这样:

self.addEventListener('activate', event => {
  event.waitUntil(clients.claim());
});

它将确保不受控制但具有活动服务工作者的其他选项卡(客户端)将由活动服务工作者控制。这意味着对资源的任何获取现在都将通过活动的服务工作者。如果没有 Clients.claim,则在重新加载页面之前不会使用 service worker。

同样,如果所有网页都已经由服务人员控制。如果检测到并安装了 NEW service worker,它通常会等到网页(客户端)的所有选项卡都关闭。下次您访问该网页时,它将激活新的 service worker,并且该网页将由它控制。

但是,如果您不关闭所有客户端并使用 skipWaiting 强制使用新服务工作者,它将立即对所有客户端激活并受到控制。这意味着从任何客户端获取资源的任何新操作现在都将立即通过您的新服务工作者。现在您不需要使用 Clients.claim 来让其他客户端开始使用您的新服务工作者。

这是我的尝试,希望对大家有所帮助。