如何在所有其他请求之前加载服务工作者?
How do I load a service worker before all other requests?
我正在尝试在页面上的所有子资源请求之前加载服务工作者,以便我可以对加载子资源的方式应用一些优化(例如,延迟加载、加载资产的缩小版本而不是完整资产)。但是,我找不到在其他子资源请求开始之前加载我的 SW 的方法。
我创建了一个简单的概念验证,说明我试图对 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>
...
这是我的 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));
});
这是我浏览器中发生的情况:
正如您在屏幕截图中看到的,即使我注册 Service Worker 的代码位于页面的最顶部,它也不会激活并开始处理请求,直到稍后,到那时一大我需要捕获的关键请求数已经被触发。
我在 Service Worker 规范的 Github 问题中发现其他人似乎正在尝试做我正在尝试完成的事情(2 年前):https://github.com/w3c/ServiceWorker/issues/1282
他们似乎建议使用 <link rel="serviceworker"...
标签来执行此操作,但由于某种原因,此 link 类型似乎已从 Chrome 中删除:https://www.chromestatus.com/feature/5682681044008960
我尝试了其他几个想法来尝试首先加载我的 SW:
- 使用
<link rel="preload"...
标签预加载我的软件
- 使用
fetch
/XMLHttpRequest
预加载我的软件
- 在 HTML 中内联 Service Worker(显然不可能)
- 通过 运行 几秒钟的 while 循环延迟页面的执行(这有点奏效,但这是一个可怕的不可预测的 hack)
我缺少任何想法或策略吗?我的 Google-fu 没能想出解决方案。
您需要先单独安装软件,然后刷新页面。然后 SW 可以为支持 SW 的页面提供内容并拦截所有其他请求。示例:fetch-progress.anthum.com
index.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.
-->
我正在尝试在页面上的所有子资源请求之前加载服务工作者,以便我可以对加载子资源的方式应用一些优化(例如,延迟加载、加载资产的缩小版本而不是完整资产)。但是,我找不到在其他子资源请求开始之前加载我的 SW 的方法。
我创建了一个简单的概念验证,说明我试图对 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>
...
这是我的 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));
});
这是我浏览器中发生的情况:
正如您在屏幕截图中看到的,即使我注册 Service Worker 的代码位于页面的最顶部,它也不会激活并开始处理请求,直到稍后,到那时一大我需要捕获的关键请求数已经被触发。
我在 Service Worker 规范的 Github 问题中发现其他人似乎正在尝试做我正在尝试完成的事情(2 年前):https://github.com/w3c/ServiceWorker/issues/1282
他们似乎建议使用 <link rel="serviceworker"...
标签来执行此操作,但由于某种原因,此 link 类型似乎已从 Chrome 中删除:https://www.chromestatus.com/feature/5682681044008960
我尝试了其他几个想法来尝试首先加载我的 SW:
- 使用
<link rel="preload"...
标签预加载我的软件 - 使用
fetch
/XMLHttpRequest
预加载我的软件
- 在 HTML 中内联 Service Worker(显然不可能)
- 通过 运行 几秒钟的 while 循环延迟页面的执行(这有点奏效,但这是一个可怕的不可预测的 hack)
我缺少任何想法或策略吗?我的 Google-fu 没能想出解决方案。
您需要先单独安装软件,然后刷新页面。然后 SW 可以为支持 SW 的页面提供内容并拦截所有其他请求。示例:fetch-progress.anthum.com
index.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.
-->