ServiceWorkerContainer: register() 方法

Baseline 已广泛支持

此功能已成熟,可跨多种设备和浏览器版本工作。它自 ⁨2018 年 4 月⁩ 起已在所有浏览器中可用。

安全上下文: 此功能仅在安全上下文(HTTPS)中可用,且支持此功能的浏览器数量有限。

注意:此功能在 Web Workers 中可用。

ServiceWorkerContainer 接口的 register() 方法用于为给定范围创建或更新一个 ServiceWorkerRegistration。如果成功,该注册会将提供的脚本 URL 与一个范围相关联,该范围随后用于将文档匹配到特定的 service worker。

每个唯一的范围只创建一个注册。如果为已存在的范围调用 register(),则该注册将使用 scriptURL 或 options 的任何更改进行更新。如果没有更改,则返回现有的注册。使用相同的范围和 scriptURL 调用 register() 不会重新启动安装过程,因此通常可以从受控页面无条件调用此方法。但是,它会发送对 service worker 脚本的网络请求,这可能会增加服务器的负载。如果这令人担忧,您可以使用 ServiceWorkerContainer.getRegistration() 检查是否已存在注册。

一个文档可能属于具有不同 service worker 和选项的多个注册的范围。浏览器会将该文档与具有最具体范围的匹配注册相关联。这确保了每个文档只运行一个 service worker。

注意: 通常最好不要定义具有重叠范围的注册。

语法

js
register(scriptURL)
register(scriptURL, options)

参数

scriptURL

service worker 脚本的 URL。注册的 service worker 文件需要具有有效的 JavaScript MIME 类型

options 可选

包含注册选项的对象。目前可用的选项有:

scope

一个字符串,表示定义 service worker 注册范围的 URL;也就是说,service worker 可以控制的 URL 的范围。

这通常被指定为相对于站点基 URL 的 URL(例如,/some/path/),这样无论从哪个页面调用注册代码,解析后的范围都是相同的。service worker 注册的默认 scope 是 service worker 脚本所在目录(相对于 scriptURL 解析 ./)。

范围应该用于指定与 service worker 相同目录或更深层目录下的文档。如果您需要更广泛的范围,可以通过 HTTP Service-Worker-Allowed 标头来实现。有关扩展 service worker 默认范围的信息,请参阅 示例 部分。

type

一个字符串,指定要创建的工作程序的类型。有效值为:

'classic'

加载的 service worker 是标准脚本。这是默认值。

'module'

加载的 service worker 是 ES 模块,并且 import 语句在 worker 上下文中可用。有关 ES 模块兼容性信息,请参阅 ServiceWorker 接口的浏览器兼容性数据表

updateViaCache

一个字符串,指示在更新期间如何使用 HTTP 缓存来处理 service worker 脚本资源。注意:这仅指 service worker 脚本及其导入,而不指这些脚本获取的其他资源。

'all'

将为主要脚本和所有导入的脚本查询 HTTP 缓存。如果在 HTTP 缓存中找不到新鲜条目,则从网络获取脚本。

'imports'

将为导入的脚本查询 HTTP 缓存,但主要脚本将始终从网络更新。如果在 HTTP 缓存中找不到导入的脚本的新鲜条目,则从网络获取它们。

'none'

不会为主要脚本或其导入的脚本使用 HTTP 缓存。所有 service worker 脚本资源都将从网络更新。

返回值

一个 Promise,它解析为一个 ServiceWorkerRegistration 对象。

异常

TypeError

scriptURLscope URL 发生错误。如果 URL 无法解析为有效 URL,或使用了非 http:https 的协议,则可能发生此情况。如果 scriptURL 不是 TrustedScriptURL,并且这是站点 Trusted Types Policy 的要求,也可能发生此情况。

如果 scriptURLscope URL 路径包含不区分大小写的 ASCII "%2f"(*)或 "%5c"(=),则也会引发该异常。

SecurityError DOMException

scriptURL 不是一个潜在可信的源,例如 localhosthttps URL。scriptURL 和范围与注册页面不是同源的。

示例

应将下面的示例结合起来阅读,以了解 service worker 范围如何应用于页面。

使用默认范围注册 service worker

以下示例通过省略 scope 的值来使用其默认值,将其设置为与脚本 URL 相同的位置。

假设 service worker 代码位于 example.com/sw.js,注册代码位于 example.com/index.html。service worker 代码将控制 example.com/index.html 以及其下的页面,例如 example.com/product/description.html

js
if ("serviceWorker" in navigator) {
  // Register a service worker hosted at the root of the
  // site using the default scope.
  navigator.serviceWorker.register("/sw.js").then(
    (registration) => {
      console.log("Service worker registration succeeded:", registration);
    },
    (error) => {
      console.error(`Service worker registration failed: ${error}`);
    },
  );
} else {
  console.error("Service workers are not supported.");
}

请注意,我们已相对于站点根目录而非当前页面注册了 scriptURL。这允许从任何页面使用相同的注册代码。

使用显式默认范围注册 service worker

下面的代码几乎相同,只是我们使用 { scope: "/" } 显式指定了范围。我们将范围指定为站点相对路径,以便可以从站点的任何位置使用相同的注册代码。

js
if ("serviceWorker" in navigator) {
  // declaring scope manually
  navigator.serviceWorker.register("./sw.js", { scope: "/" }).then(
    (registration) => {
      console.log("Service worker registration succeeded:", registration);
    },
    (error) => {
      console.error(`Service worker registration failed: ${error}`);
    },
  );
} else {
  console.error("Service workers are not supported.");
}

此范围与默认范围相同,因此注册适用于与上一个示例完全相同的页面。请注意,如果我们在上一个示例之后运行此代码,浏览器应该会识别出我们正在更新现有注册而不是新的注册。

使用页面相对 URL 注册 service worker

没有什么阻止您使用页面相对 URL,只是这使得移动页面变得更加困难,而且这样做很容易意外创建不需要的注册。

在此示例中,service worker 代码位于 example.com/product/sw.js,注册代码位于 example.com/product/description.html。我们为 scriptURLscope 使用了相对于当前目录的 URL,当前目录是调用 register() 的页面的基础 URL(example.com/product/)。service worker 适用于 example.com/product/ 下的资源。

js
if ("serviceWorker" in navigator) {
  // declaring scope manually
  navigator.serviceWorker.register("./sw.js", { scope: "./" }).then(
    (registration) => {
      console.log("Service worker registration succeeded:", registration);
    },
    (error) => {
      console.error(`Service worker registration failed: ${error}`);
    },
  );
} else {
  console.error("Service workers are not supported.");
}

使用 Service-Worker-Allowed 扩展 service worker 范围

除非服务器在 service worker 脚本上使用 Service-Worker-Allowed 标头指定了更广泛的最大范围,否则 service worker 的范围不能比其自身位置更广。当您需要比默认值更窄的范围时,请使用 scope 选项。

以下代码如果包含在站点根目录的 example.com/index.html 中,则仅适用于 example.com/product 下的资源。

js
if ("serviceWorker" in navigator) {
  // declaring scope manually
  navigator.serviceWorker.register("./sw.js", { scope: "/product/" }).then(
    (registration) => {
      console.log("Service worker registration succeeded:", registration);
    },
    (error) => {
      console.error(`Service worker registration failed: ${error}`);
    },
  );
} else {
  console.error("Service workers are not supported.");
}

如上所述,服务器可以通过在服务 sw.js 时设置 Service-Worker-Allowed 标头来更改默认范围。这允许 scope 选项设置在 service worker 位置定义的路径之外。

如果以下代码包含在 example.com/product/index.html 中,并且服务器在服务 sw.js 时将 Service-Worker-Allowed 标头设置为 /https://example.com/,则它将适用于 example.com 下的所有资源。如果服务器未设置该标头,则请求的 scope 过宽,导致 service worker 注册失败。

js
if ("serviceWorker" in navigator) {
  // Declaring a broadened scope
  navigator.serviceWorker.register("./sw.js", { scope: "/" }).then(
    (registration) => {
      // The registration succeeded because the Service-Worker-Allowed header
      // had set a broadened maximum scope for the service worker script
      console.log("Service worker registration succeeded:", registration);
    },
    (error) => {
      // This happens if the Service-Worker-Allowed header doesn't broaden the scope
      console.error(`Service worker registration failed: ${error}`);
    },
  );
} else {
  console.error("Service workers are not supported.");
}

规范

规范
Service Workers
# navigator-service-worker-register

浏览器兼容性

另见