首页 > 解决方案 > 如何在所有其他请求之前加载服务人员?

问题描述

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

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

这是我的 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>
    ...

这是我的服务人员:

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));
});

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

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

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

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

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

我缺少任何想法或策略吗?我的 Google-fu 未能让我想出一个解决方案。

标签: javascriptservice-workerprogressive-web-apps

解决方案


您需要先单独安装软件,然后刷新页面。然后,SW 可以为启用 SW 的页面提供内容并拦截所有其他请求。示例: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>

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
  }
});

index-sw-enabled.html

<!-- 
  This page shows after SW installs.
  Put your main app content on this page.
-->

推荐阅读