Clients API:service worker 对客户端对象的访问能力
一句话: Clients 接口在 service worker 内部通过 self.clients 访问,提供对符合查询选项的 Client 对象(窗口、worker)的访问——通过 matchAll({ includeUncontrolled: true }),还可以包含与该 service worker 共享同一 storage key/同源、但未被其控制、也未与其注册关联的客户端。
该特性仅在 service worker 中可用。
// 在 service worker 内部self.clients;| 方法 | 返回值 | 作用 |
|---|---|---|
Clients.get(id) |
Promise<Client | undefined> |
返回与给定 id 匹配的 Client;若没有匹配的客户端则解析为 undefined。 |
Clients.matchAll(options) |
Promise<Array<Client>> |
返回一个 Client 对象数组;默认只返回受控客户端,options 参数可控制返回哪些类型的客户端,包括尚未受控的客户端。 |
Clients.openWindow(url) |
Promise<WindowClient | null> |
为给定的 URL 打开一个新的浏览器窗口;若平台无法为其返回同源的 WindowClient,则解析为 null。 |
Clients.claim() |
一个解析为 undefined 的 Promise |
让处于激活状态的 service worker 将自己设置为其作用域内所有客户端的控制者。 |
查找已打开的聊天窗口并聚焦,或在未找到时打开一个新窗口,然后向其发送消息:
addEventListener("notificationclick", (event) => { event.waitUntil( (async () => { const allClients = await clients.matchAll({ includeUncontrolled: true, });
let chatClient;
// 看看是否已经有一个聊天窗口打开: for (const client of allClients) { const url = new URL(client.url);
if (url.pathname === "/chat/") { // 太好了,用它! client.focus(); chatClient = client; break; } }
// 如果没有找到已有的聊天窗口, // 打开一个新的: chatClient ??= await clients.openWindow("/chat/");
// 向该客户端发送消息: chatClient.postMessage("New chat messages!"); })(), );});Clients 接口属于 Baseline 广泛可用:它已经在众多设备和浏览器版本中得到充分确立并可正常使用,自 2018 年 4 月起已在各浏览器中可用。
- 当 service worker 需要查找它尚未控制的窗口时,使用带
includeUncontrolled选项的clients.matchAll()——默认情况下matchAll()只返回受控客户端。 - 处理
clients.get(id)解析为undefined、clients.openWindow(url)解析为null的情况(即找不到匹配客户端时)。 - 如果 service worker 需要立即接管现有客户端,而不是等到下一次导航,在
activate事件处理函数中调用clients.claim()。 - 仅在用户手势(例如点击通知)的响应中使用
clients.openWindow(),遵循上面示例展示的模式。
- Navigation preload — 另一个通过类似作用域 API 暴露的 service worker 能力