共享跨多个服务工作者定义的提取处理程序逻辑 [英] Sharing fetch handler logic defined across multiple service workers

查看:45
本文介绍了共享跨多个服务工作者定义的提取处理程序逻辑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个讨论之后,哪里有评论说

通过覆盖 self.fetch、self.XMLHttpRequest 和 self.caches(对于cache.add/addAll)?看起来这些可以让您在主软件脚本看到它们之前拦截网络请求并操纵响应.

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.

我一直在寻找任何有关此类内容的文档,但似乎找不到任何文档.

I have been looking out for any documentation that speaks of such stuff, and can not seem to find any.

在我只是需要 多个服务工作者在一个范围内共存的情况下,

In a scenario where I simply need multiple service workers to co exist in a single scope,

在其中一个使用 importScripts 导入另一个的事件处理程序后,

After having an importScripts in one of them to import the event handlers of the other,

我将如何修补抓取/避免抓取竞争/让两个抓取处理程序都工作?

How exactly would I patch a fetch / avoid a fetch race / have both the fetch handlers work?

推荐答案

这里有几件事要介绍:

单一范围内的多个 Service Worker

对于给定的范围只能有一个活动的 Service Worker.如果您尝试注册两个具有相同作用域的不同 Service Worker 脚本,则第二次注册将触发 service worker 更新流程:

There can only be one active service worker for a given scope. If you attempt to register two different service worker scripts that each have the same scope, the second registration will trigger the 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()sw2.js 中的 self.clients.claim().一旦 sw2.js 激活,sw1.js 将被标记为冗余.

The exact timing for when sw2.js will activate and take control over any existing clients depends on whether you're using self.skipWaiting() and self.clients.claim() inside of sw2.js. Once sw2.js activates, sw1.js will be marked as redundant.

问我认为是同一个问题的另一种方式是您是否可以让多个服务工作者同时控制同一个客户端页面.答案是否定的,您最多可以让一个 Service Worker 控制任何客户端页面,并且只有该 Service Worker 能够响应源自该页面的 fetch 事件.

Another way of asking what I think is the same question is whether you can have multiple service workers controlling the same client page at the same time. The answer is no, you can have at most one service worker controlling any client page, and only that service worker will be able to respond to fetch events originating from the page.

使用 importScripts 共享通用处理程序

使用importScripts() 引入在不同 JavaScript 文件中定义的逻辑听起来是一种合理的方法.以这种方式使用 importScripts() 时需要记住以下几点:

Instead of attempting to register multiple service workers with the same scope, using importScripts() to pull in logic that's defined in a different JavaScript file sounds like a reasonable approach. There are a few things to keep in mind when using importScripts() in this fashion:

  • importScripts() 需要在 Service Worker 代码的初始启动执行期间调用,而不是在事件处理程序中调用.IE.不支持 importScripts() 的延迟加载".
  • importScripts() 同步执行文件中的所有代码,按照它们列出的顺序一个一个地执行.您可以在自己导入的文件中包含多个 importScripts()importScripts(),它们都将按定义的顺序执行.
  • 在导入的脚本中,self 将设置为相同的 ServiceWorkerGlobalScope 如果代码位于顶级服务工作线程中,则将使用该代码.即,在导入的脚本内部或在顶级 Service Worker 内部调用 self.addEventListener() 之间没有区别.
  • (这与您的问题没有直接关系,但很高兴知道:)默认情况下将缓存通过 importScripts() 引用的文件,使用内置于用于缓存顶级 Service Worker 文件的浏览器.虽然正在对 Service Worker 规范进行一些更改以改变这一点,但截至目前,这些缓存的 importScripts() 文件将无限期地使用,只要它们的文件名不改变.因此,最佳做法是在 importScripts() 引用的任何文件名中包含版本号或哈希值.
  • importScripts() needs to be called during the initial startup execution of your service worker code, not inside an event handler. I.e. "lazy-loading" of importScripts() is not supported.
  • importScripts() executes all the of the code inside of the file(s) synchronously, one by one, in the order in which they're listed. You can have multiple importScripts(), or importScripts() inside of files that are themselves imported, and they'll all execute in a defined order.
  • Inside an imported script, self will be set to the same ServiceWorkerGlobalScope that would be used if the code were in the top-level service worker. I.e., there's no difference between calling self.addEventListener() inside of an imported script or inside of the top-level service worker.
  • (This isn't directly related to your question, but it's good to know:) The files referenced via importScripts() will be cached by default, using the same mechanism that's built in to the browser for caching your top-level service worker file. While there are some changes to the service worker specification underway to change this, as of right now, those cached importScripts() files will be used indefinitely as long as their filenames don't change. So a best practice is to either include a version number or a hash in the file names of anything referenced with importScripts().

多个获取事件处理程序

当您多次调用 self.addEventListener('fetch') 时会发生什么?

What happens when you have multiple calls to self.addEventListener('fetch')?

从上一节我们知道,这些多次调用是源自 importScripts() 资源内部还是顶级 Service Worker 并不相关.它们都在相同的全局范围内运行.

From the previous section we know that it's not relevant whether those multiple calls originate inside of an importScripts() resource or the top-level service worker. They both operate on the same global scope.

行为定义明确:当客户端页面发出请求时,它将依次触发控制服务工作者的fetch处理程序,按照它们的顺序注册,直到第一次调用 event.respondWith().一个 fetch 事件处理程序调用 respondWith(),不会触发其他 fetch 事件处理程序,并且该处理程序的唯一责任(最终)返回 对客户端页面的响应.

The behavior is well-defined: when a client page makes a request, it will trigger the fetch handlers of the controlling service worker one by one, in the order in which they were registered, until the first call is made to event.respondWith(). One one fetch event handler calls respondWith(), no other fetch event handlers will be triggered, and it's the sole responsibility of that handler to (eventually) return a Response to the client page.

由于 self.addEventlistener('fetch') 调用的顺序很重要,请确保以适当的顺序列出 importScripts() 中的文件,并在您在顶级服务工作线程中定义任何 fetch 事件处理程序之前或之后,包括您对 importScripts() 的调用,具体取决于您希望优先使用哪个.

Since the order in which your self.addEventlistener('fetch') calls matter, make sure that you list the files in your importScripts() in an appropriate order, and either include your call to importScripts() before or after you define any fetch event handlers in your top-level service worker, depending on which you want to take precedence.

虽然您可以使用条件逻辑来确定是否调用 event.respondWith(),但该逻辑不能是异步的,因为 Service Worker 不会等待查看 event.respondWith() 被调用.它需要同步移动到下一个 event 处理程序(假设有一个).

While you can use conditional logic to determine whether or not to call event.respondWith(), that logic can't be asynchronous, since the service worker won't wait to see whether event.respondWith() is called. It needs to synchronously move on to the next event handler (assuming there is one).

因此在 fetch 处理程序中,您可以使用条件逻辑,如

So inside a fetch handler, you can use conditional logic like

// This can be executed synchronously.
if (event.request.url.endsWith('.html')) {
  event.respondWith(...);
}

但是您不能使用条件逻辑,例如:

but you can't use conditional logic like:

// 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(...);
  }
});

您可以使用实时代码示例探索是否要亲自查看多处理程序行为.

There's a live code sample that you can explore if you want to see the multiple-handlers behavior for yourself.

这篇关于共享跨多个服务工作者定义的提取处理程序逻辑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆