共享跨多个服务工作者定义的获取处理程序逻辑
Sharing fetch handler logic defined across multiple service workers
关注 This Discussion,其中有评论提到
修补 Fetch
by overriding self.fetch, self.XMLHttpRequest, and self.caches (for
cache.add/addAll)? It would seem these would let you intercept network requests and manipulate responses before the main SW script sees them.
我一直在寻找有关此类内容的任何文档,但似乎找不到。
在我只是需要 multiple
service worker 共存于单个范围的情况下,
其中一个中有 importScripts
以导入另一个的事件处理程序后,
我将如何准确地修补抓取/避免抓取竞争/使两个抓取处理程序都能正常工作?
这里有几件事要讲:
单个作用域中的多个 Service Worker
给定范围内只能有一个活动的服务工作者。如果您尝试注册两个具有相同作用域的不同服务工作者脚本,则第二次注册将触发 service worker update flow:
// There's an implied default scope of '/'.
// See
navigator.serviceWorker.register('/sw1.js');
// If called later on, this will trigger the update flow.
// You'll only end up with one of the two being active.
navigator.serviceWorker.register('/sw2.js');
sw2.js
激活并控制任何现有客户端的确切时间取决于您是否在 sw2.js
中使用 self.skipWaiting()
和 self.clients.claim()
。一旦 sw2.js
激活,sw1.js
将被标记为冗余。
另一种问我认为是同一个问题的方式是你是否可以让多个服务工作者同时控制同一个客户端页面。答案是否定的,您最多可以让一个 service worker 控制任何客户端页面,并且只有该 service worker 才能响应来自该页面的 fetch
事件。
使用 importScripts 共享通用处理程序
与其尝试在同一范围内注册多个服务工作者,不如使用 importScripts()
引入在不同 JavaScript 文件中定义的逻辑,这听起来是一种合理的方法。以这种方式使用 importScripts()
时需要注意以下几点:
importScripts()
需要在服务工作者代码的初始启动执行期间调用,而不是在事件处理程序中调用。 IE。不支持 importScripts()
的 "lazy-loading"。
importScripts()
同步执行文件内的所有代码,一个接一个,按照它们列出的顺序。您可以在自己导入的文件中包含多个 importScripts()
或 importScripts()
,它们都将按定义的顺序执行。
- 在导入的脚本中,
self
将设置为相同的 ServiceWorkerGlobalScope
,如果代码位于顶级服务工作者中,则将使用相同的 ServiceWorkerGlobalScope
。也就是说,在导入的脚本内部或顶级服务工作者内部调用 self.addEventListener()
没有区别。
- (这与您的问题没有直接关系,但很高兴知道:)默认情况下将缓存通过
importScripts()
引用的文件,使用浏览器内置的相同机制进行缓存您的顶级服务工作者文件。虽然正在对 Service Worker 规范进行一些更改以改变这一点,但截至目前,只要文件名不变,那些缓存的 importScripts()
文件将被无限期使用。因此,最佳做法是在 importScripts()
. 引用的任何内容的文件名中包含版本号或哈希值
多次获取事件处理程序
多次调用 self.addEventListener('fetch')
时会发生什么?
从上一节我们知道,这些多次调用是起源于 importScripts()
资源还是顶级服务工作者内部并不相关。它们都在相同的全局范围内运行。
行为定义明确:当客户端页面发出请求时,它会一个接一个地触发控制 service worker 的 fetch
处理程序,按照它们的顺序已注册 ,直到第一次调用 event.respondWith()
。一个 fetch
事件处理程序调用 respondWith()
,不会触发其他获取事件处理程序,并且该处理程序(最终)return 一个 Response
的唯一责任客户页面。
由于您的 self.addEventlistener('fetch')
调用的顺序很重要,请确保您以适当的顺序列出 importScripts()
中的文件,并在之前包含对 importScripts()
的调用或在您的顶级服务工作者中定义任何 fetch
事件处理程序之后,具体取决于您想要优先考虑的事件处理程序。
虽然您可以使用条件逻辑来确定是否调用 event.respondWith()
,但该逻辑不能是异步的,因为 service worker 不会等着看 event.respondWith()
是否被调用.它需要同步移动到下一个 event
处理程序(假设有一个)。
因此在 fetch
处理程序中,您可以使用条件逻辑,例如
// This can be executed synchronously.
if (event.request.url.endsWith('.html')) {
event.respondWith(...);
}
但是你不能使用像这样的条件逻辑:
// caches.match() is asynchronous, and the service worker will have
// moved on to the next `fetch` handler before it completes.
caches.match('index.html').then(response => {
if (response) {
event.respondWith(...);
}
});
如果您想亲自查看多处理程序行为,可以探索 live code sample。
关注 This Discussion,其中有评论提到
修补 Fetch
by overriding self.fetch, self.XMLHttpRequest, and self.caches (for cache.add/addAll)? It would seem these would let you intercept network requests and manipulate responses before the main SW script sees them.
我一直在寻找有关此类内容的任何文档,但似乎找不到。
在我只是需要 multiple
service worker 共存于单个范围的情况下,
其中一个中有 importScripts
以导入另一个的事件处理程序后,
我将如何准确地修补抓取/避免抓取竞争/使两个抓取处理程序都能正常工作?
这里有几件事要讲:
单个作用域中的多个 Service Worker
给定范围内只能有一个活动的服务工作者。如果您尝试注册两个具有相同作用域的不同服务工作者脚本,则第二次注册将触发 service worker update flow:
// There's an implied default scope of '/'.
// See
navigator.serviceWorker.register('/sw1.js');
// If called later on, this will trigger the update flow.
// You'll only end up with one of the two being active.
navigator.serviceWorker.register('/sw2.js');
sw2.js
激活并控制任何现有客户端的确切时间取决于您是否在 sw2.js
中使用 self.skipWaiting()
和 self.clients.claim()
。一旦 sw2.js
激活,sw1.js
将被标记为冗余。
另一种问我认为是同一个问题的方式是你是否可以让多个服务工作者同时控制同一个客户端页面。答案是否定的,您最多可以让一个 service worker 控制任何客户端页面,并且只有该 service worker 才能响应来自该页面的 fetch
事件。
使用 importScripts 共享通用处理程序
与其尝试在同一范围内注册多个服务工作者,不如使用 importScripts()
引入在不同 JavaScript 文件中定义的逻辑,这听起来是一种合理的方法。以这种方式使用 importScripts()
时需要注意以下几点:
importScripts()
需要在服务工作者代码的初始启动执行期间调用,而不是在事件处理程序中调用。 IE。不支持importScripts()
的 "lazy-loading"。importScripts()
同步执行文件内的所有代码,一个接一个,按照它们列出的顺序。您可以在自己导入的文件中包含多个importScripts()
或importScripts()
,它们都将按定义的顺序执行。- 在导入的脚本中,
self
将设置为相同的ServiceWorkerGlobalScope
,如果代码位于顶级服务工作者中,则将使用相同的ServiceWorkerGlobalScope
。也就是说,在导入的脚本内部或顶级服务工作者内部调用self.addEventListener()
没有区别。 - (这与您的问题没有直接关系,但很高兴知道:)默认情况下将缓存通过
importScripts()
引用的文件,使用浏览器内置的相同机制进行缓存您的顶级服务工作者文件。虽然正在对 Service Worker 规范进行一些更改以改变这一点,但截至目前,只要文件名不变,那些缓存的importScripts()
文件将被无限期使用。因此,最佳做法是在importScripts()
. 引用的任何内容的文件名中包含版本号或哈希值
多次获取事件处理程序
多次调用 self.addEventListener('fetch')
时会发生什么?
从上一节我们知道,这些多次调用是起源于 importScripts()
资源还是顶级服务工作者内部并不相关。它们都在相同的全局范围内运行。
行为定义明确:当客户端页面发出请求时,它会一个接一个地触发控制 service worker 的 fetch
处理程序,按照它们的顺序已注册 ,直到第一次调用 event.respondWith()
。一个 fetch
事件处理程序调用 respondWith()
,不会触发其他获取事件处理程序,并且该处理程序(最终)return 一个 Response
的唯一责任客户页面。
由于您的 self.addEventlistener('fetch')
调用的顺序很重要,请确保您以适当的顺序列出 importScripts()
中的文件,并在之前包含对 importScripts()
的调用或在您的顶级服务工作者中定义任何 fetch
事件处理程序之后,具体取决于您想要优先考虑的事件处理程序。
虽然您可以使用条件逻辑来确定是否调用 event.respondWith()
,但该逻辑不能是异步的,因为 service worker 不会等着看 event.respondWith()
是否被调用.它需要同步移动到下一个 event
处理程序(假设有一个)。
因此在 fetch
处理程序中,您可以使用条件逻辑,例如
// This can be executed synchronously.
if (event.request.url.endsWith('.html')) {
event.respondWith(...);
}
但是你不能使用像这样的条件逻辑:
// caches.match() is asynchronous, and the service worker will have
// moved on to the next `fetch` handler before it completes.
caches.match('index.html').then(response => {
if (response) {
event.respondWith(...);
}
});
如果您想亲自查看多处理程序行为,可以探索 live code sample。