如何在所有其他请求之前加载 Service Worker?

jam*_*slk 7 javascript service-worker progressive-web-apps

我试图在页面上的所有子资源请求之前加载服务工作人员,以便我可以对子资源的加载方式应用一些优化(例如延迟加载、加载资产的缩小版本而不是完整资产)。但是,我找不到在其他子资源请求开始之前加载我的软件的方法。

我创建了一个简单的概念验证,说明我试图对我的 Service Worker 处理的任何请求执行 401 操作(只是为了更容易找到我的软件何时开始处理请求)。

这是我的 HTML:

<!doctype html>
<head>
    <script>
        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('/dl-wps-sw.js', { scope: '/' }).then(function (registration) {
                console.log('Service Worker registration successful with scope: ', registration.scope);
            }, function (err) {
                console.error(err);
            });
        }
    </script>
    ...
Run Code Online (Sandbox Code Playgroud)

这是我的 Service Worker:

self.addEventListener('install', function (event) {
    self.skipWaiting();
});

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

self.addEventListener('fetch', (event) => {
    const init = {status: 401, statusText: 'Blocked!'};
    event.respondWith(new Response(null, init));
});

Run Code Online (Sandbox Code Playgroud)

这是我的浏览器中发生的情况: 在此输入图像描述

正如您在屏幕截图中看到的,即使我注册 Service Worker 的代码位于页面的最顶部,但直到稍后它才会激活并开始处理请求,到那时我会收到大量关键请求需要抓住已经发射的。

我发现其他人似乎正在尝试做我想要完成的事情(两年前),在 Service Worker 规范的 Github 问题中: https: //github.com/w3c/ServiceWorker/issues/1282

他们似乎建议使用<link rel="serviceworker"...标签来执行此操作,但由于某种原因,此链接类型似乎已从 Chrome 中删除:https ://www.chromestatus.com/feature/5682681044008960

我尝试了其他几种想法来尝试首先加载我的软件:

  • 使用<link rel="preload"...标签预加载我的软件
  • fetch/预加载我的软件XMLHttpRequest
  • 在 HTML 中内联 Service Worker(显然不可能)
  • 通过运行 while 循环几秒钟来延迟页面的执行(这有点有效,但这是一个可怕的不可预测的黑客)

我缺少任何想法或策略吗?我的 Google-fu 没能找到解决方案。

Ant*_*ris 7

您需要先单独安装软件,然后刷新页面。然后,软件可以为支持软件的页面提供内容并拦截所有其他请求。示例:fetch-progress.anthum.com

索引.html

<p>Installing Service Worker, please wait...</p>

<script>
  navigator.serviceWorker.register('sw.js')
  .then(reg => {
    if (reg.installing) {
      const sw = reg.installing || reg.waiting;
      sw.onstatechange = function() {
        if (sw.state === 'installed') {
          // SW installed.  Refresh page so SW can respond with SW-enabled page.
          window.location.reload();
        }
      };
    } else if (reg.active) {
      // something's not right or SW is bypassed.  previously-installed SW should have redirected this request to different page
      handleError(new Error('Service Worker is installed and not redirecting.'))
    }
  })
  .catch(handleError)

  function handleError(error) {}
</script>
Run Code Online (Sandbox Code Playgroud)

sw.js

self.addEventListener('fetch', event => {
  const url = event.request.url;
  const scope = self.registration.scope;

  // serve index.html with service-worker-enabled page
  if (url === scope || url === scope+'index.html') {
    const newUrl = scope+'index-sw-enabled.html';
    event.respondWith(fetch(newUrl))
  } else {
    // process other files here
  }
});
Run Code Online (Sandbox Code Playgroud)

索引-sw-enabled.html

<!-- 
  This page shows after SW installs.
  Put your main app content on this page.
-->
Run Code Online (Sandbox Code Playgroud)