对 Chrome 71 中的 cache.addAll() 和 importScripts() 进行了调整

使用服务工作器Cache Storage API 的开发者应留意 Chrome 71 中即将推出的两项小幅变更。这两项变更使 Chrome 的实现更符合规范和其他浏览器。

禁止异步 importScripts()

importScripts() 会指示您的主 Service Worker 脚本暂停其当前执行,从给定网址下载其他代码,并在当前的全局范围中运行该脚本以完成操作。完成此操作后,主 Service Worker 脚本将继续执行。当您出于组织原因想要将主要服务工件脚本拆分为更小的部分,或者提取第三方代码以向服务工件添加功能时,importScripts() 会派上用场。

浏览器会尝试通过自动缓存通过 importScripts() 拉入的所有内容来缓解“下载并运行一些同步代码”可能存在的性能问题,这意味着在初始下载后,执行导入的代码所涉及的开销非常小。

不过,为了实现这一点,浏览器需要知道在初始安装后,不会向服务工作线程导入任何“意外”代码。根据服务工作线程规范,调用 importScripts() 应仅在同步执行顶级服务工作线程脚本期间有效,或者在需要时在 install 处理程序内异步调用。

在 Chrome 71 之前,在 install 处理程序之外异步调用 importScripts() 会正常运行。从 Chrome 71 开始,这些调用会抛出运行时异常(除非之前在 install 处理程序中导入了相同的网址),与其他浏览器中的行为一致。

与以下代码不同:

// This only works in Chrome 70 and below.
self.addEventListener('fetch', event => {
  importScripts('my-fetch-logic.js');
  event.respondWith(self.customFetchLogic(event));
});

您的服务工件代码应如下所示:

// Move the importScripts() to the top-level scope.
// (Alternatively, import the same URL in the install handler.)
importScripts('my-fetch-logic.js');
self.addEventListener('fetch', event => {
  event.respondWith(self.customFetchLogic(event));
});

废弃传递给 cache.addAll() 的重复网址

如果您将 Cache Storage API 与服务工件搭配使用,则 Chrome 71 中还有一项与相关规范保持一致的小更改。当同一网址多次传递给对 cache.addAll() 的单次调用时,规范规定调用返回的 Promise 应被拒绝。

在 Chrome 71 之前,系统不会检测到这种情况,并且会有效忽略重复的网址。

Chrome 控制台中警告消息的屏幕截图
从 Chrome 71 开始,您会看到控制台中记录的警告消息。

此日志记录是 Chrome 72 的先兆,在该版本中,重复网址将导致 cache.addAll() 拒绝,而不仅仅是记录警告。如果您在传递给 InstallEvent.waitUntil() 的 promise 链中调用 cache.addAll()(按照常见做法),这种拒绝可能会导致 Service Worker 安装失败。

以下是您可能会遇到麻烦的方法:

const urlsToCache = [
  '/index.html',
  '/main.css',
  '/app.js',
  '/index.html', // Oops! This is listed twice and should be removed.
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('my-cache').then(cache => cache.addAll(urlsToCache))
  );
});

此限制仅适用于传递到 cache.addAll() 的实际网址,缓存最终是两个具有不同网址的等效响应(如 '/''/index.html')不会触发拒绝。

广泛测试您的服务 worker 实现

目前,所有主流的“长效”浏览器广泛实现了 Service Worker。如果您定期针对多种浏览器测试渐进式 Web 应用,或者有大量用户不使用 Chrome,那么您可能已经检测到不一致性并更新了代码。不过,万一您在其他浏览器中没有注意到这种行为,我们想先说明这一变化,然后再更改 Chrome 的行为。