在This Discussion之后,有一条评论提到
修补提取
通过覆盖self.fetch,self.XMLHttpRequest和self.caches(用于
cache.add / addAll)?看起来这些可以让您在主SW脚本看到它们之前拦截网络请求并处理响应。
我一直在寻找有关此类资料的任何文档,而且似乎找不到任何文档。
在我只需要multiple
服务人员在一个范围内共存的情况下,
在其中一个importScripts
中导入另一个的事件处理程序后,
我将如何精确修补获取/避免获取竞赛/两个获取处理程序均正常工作?
最佳答案
这里有几件事要讲:
同一范围内的多个服务人员
给定范围只能有一个活动的服务工作者。如果您尝试注册两个具有相同范围的两个不同的服务工作者脚本,则第二次注册将触发service worker update flow:
// There's an implied default scope of '/'.
// See https://stackoverflow.com/a/33881341/385997
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
何时激活并控制任何现有客户端的确切时间取决于您是否在self.skipWaiting()
中使用self.clients.claim()
和sw2.js
。 sw2.js
激活后,sw1.js
将被标记为冗余。提出我认为相同问题的另一种方法是,是否可以让多个服务工作者同时控制同一客户端页面。答案是否定的,您最多可以有一个服务工作者来控制任何客户端页面,只有该服务工作者才能响应源自该页面的
fetch
事件。使用importScripts共享公共处理程序
使用
importScripts()
引入不同JavaScript文件中定义的逻辑,而不是尝试注册具有相同作用域的多个服务工作者,这听起来像是一种合理的方法。以这种方式使用importScripts()
时,需要牢记以下几点:importScripts()
需要在服务工作者代码的初始启动执行过程中调用,而不是在事件处理程序中调用。即不支持importScripts()
的“延迟加载”。importScripts()
按照列出顺序依次同步执行文件中的所有代码。您可以在自己导入的文件中包含多个importScripts()
或importScripts()
,它们都将按定义的顺序执行。在导入的脚本中,
self
将设置为与代码在顶级服务工作程序中时使用的相同的ServiceWorkerGlobalScope
。也就是说,在导入的脚本内部或顶级服务工作者内部调用self.addEventListener()
之间没有什么区别。(这与您的问题没有直接关系,但是很高兴知道:)默认情况下,将使用与浏览器内置的用于缓存顶级服务工作程序文件的机制相同的机制缓存通过
importScripts()
引用的文件。 。尽管正在对服务工作者规范进行一些更改以进行更改,但是从现在开始,只要文件名没有更改,那些缓存的importScripts()
文件将被无限期使用。因此,最佳实践是在使用importScripts()
引用的任何文件的文件名中包括版本号或哈希。多个提取事件处理程序
当您多次呼叫
self.addEventListener('fetch')
时会发生什么?从上一节中我们知道,这些多次调用是在
importScripts()
资源内部还是在顶级服务工作者内部发起的,这无关紧要。它们都在相同的全局范围内运行。行为是明确定义的:当客户端页面发出请求时,它将按注册它们的顺序逐个触发控制服务工作程序的
fetch
处理程序,直到第一次调用event.respondWith()
事件处理程序调用fetch
,将不会触发其他提取事件处理程序,并且该处理程序的唯一责任是(最终)将respondWith()
返回到客户端页面。由于
Response
调用的顺序很重要,因此请确保以适当的顺序列出self.addEventlistener('fetch')
中的文件,并在定义任何importScripts()
事件处理程序之前或之后包括对importScripts()
的调用。您的顶级服务工作者,具体取决于您要优先考虑哪个。尽管您可以使用条件逻辑来确定是否调用
fetch
,但是该逻辑不能是异步的,因为服务工作者不会等着看是否调用了event.respondWith()
。它需要同步移动到下一个event.respondWith()
处理程序(假设有一个)。因此,在
event
处理程序中,您可以使用条件逻辑,例如// 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。
关于javascript - 在多个服务 worker 之间共享定义的提取处理程序逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45257602/