Service Worker 获取事件不会为 Service Worker 本身触发

Service Worker fetch event not triggered for service worker itself

我注意到当服务工作者脚本本身在浏览器中加载时,不再触发服务工作者的获取事件。例如,当我们有一个新版本的 service worker 时,旧的 service worker 的 fetch 事件不会被触发。因此,旧的 service worker 无法再检查新的 service worker 的内容。

我确信这以前是可能的,我想知道这是否是一个错误,或者是否对此进行了任何更改。我没有在官方存储库或 W3C 草案中找到与此更改相关的任何内容。

为了验证 fetch 事件没有被触发,我编写了一个带有版本号的小示例 service worker(见代码)。我已经通过以下方式对其进行了测试:

  1. 安装第一个版本的 service worker
  2. 将版本号增加到两个。
  3. 重新加载页面 -> 以便在浏览器中安装新的 sw.js 文件。
  4. 检查 chrome 日志 -> ChromeLogs

示例'sw.js':

const version = 1;
console.log(`SW with v${version} executed`);

async function onFetch(event) {
    // Not triggered for sw.js
    console.log(`fetching: ${event.request.url} with v${version}`);
    return await fetch(event.request);
}

async function onInstall() {
    console.log(`sw v${version} install`);
    await self.skipWaiting();
}

async function onActivate() {
    console.log(`sw v${version} activate`);
    await self.clients.claim();
}

self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
self.addEventListener('install', event => event.waitUntil(onInstall()));
self.addEventListener('activate', event => event.waitUntil(onActivate()));

正如我们从日志中看到的,sw.js 文件没有被获取,但是在安装新的 service worker 之前获取了另一个文件(test.js)。我包含了 test.js javascript 文件以查看服务人员是否正在获取任何内容。所以从这个测试中我们可以看到服务工作者脚本本身没有触发 fetch 事件。

我想知道的是,有没有什么方法可以在新服务工作者 javascript 文件加载到旧服务工作者之前获取它?是否有任何其他事件使这成为可能?我不需要拦截脚本来执行或替换旧的 service worker。我只想在加载之前检查新服务工作者的内容。

编辑:

<html>
    <body>
        <h1>hello</h1>
        <script src="test.js"></script>
        <button onclick="runFetch()">fetch</button>
        <h2 id="swVersion"></h2>
        <script>
            navigator.serviceWorker.register('/sw.js'); // First Installation
            fetch('/sw.js'); // Triggers fetch event, but is independent from update routine.
            async function runFetch() {
                console.log(await fetch('/sw.js'));
            }
        </script>
    </body>
</html>

service worker update check that is initiated by the browser always bypasses all service worker fetch handlers. It might end up being fulfilled by the HTTP Cache, although all modern browsers default 也绕过 HTTP 缓存并直接进入网络。

我非常有信心,在执行服务工作人员更新检查时,没有浏览器触发过之前服务工作人员的 fetch 事件处理程序,因为更新请求的明确 forbidden by the service worker specification (the service-workers mode 是必需的设置为 'none')。这有助于开发人员避免以下情况:如果旧服务工作人员在为新服务工作人员处理 fetch 事件时做错了一些事情,可能会得到 "stuck"。

我不确定您为什么会有其他想法 — 也许您正在考虑 HTTP 缓存交互。或者您可能正在考虑这样一种场景,其中网络应用程序显式调用 fetch('service-worker.js') 来检查给定 URL 是否存在服务工作者, 触发控制给定页面的服务工作者的 fetch 处理程序。但是调用 fetch('service-worker.js') 与 service worker 更新检查有很大不同。