Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider mechanisms to bypass the service worker for things that we know won't be in it's cache #1026

Open
n8schloss opened this issue Dec 13, 2016 · 17 comments

Comments

@n8schloss
Copy link

The Problem

There will always be some number of resources that we cannot cache in the Service Worker. Perhaps this is segments of a 360 VR video or something like a profile picture that just changed. In many case it's possible that the client will know in advance that the Service Worker does not have this resource cached yet the request for it still need to go through the Service Worker.

Right now the process of sending a request from the main thread to a Service Worker can take a few milliseconds in many implementations. Then we have to wait on the event loop in the Service Worker (which we always have to do even in the best case scenario). Facebook tends to send large bursts of resource requests as the page loads. If we send 40 or so requests from the window at once, while the first few may be quick, the other events get tacked onto the end of the Service Worker event loop and end up getting delayed quite a bit before they can hit the network. Even though the Service Worker won't call respondWith for these events they still get delayed by the busy Service Worker event queue.

Proposed Solution

The window will generally know it has a resources that there's no way the Service Worker has in cache. It'd be nice if there was a way for the service worker to be totally bypassed when this resource is requested. Perhaps this is an API on the service worker registration that lets you mark URLs as bypassable, perhaps we add this as a fetch option and let you add fetch options to html tags, perhaps we come up with some url scheme that let's you bypass the sw. I'm not sure what the right solution is, but I'd like to start thinking about what one could be :)

@wanderview
Copy link
Member

Sounds like another use case solved by Jake's static routing proposal:

#920 (comment)

I do wonder how much headroom there is for this kind of optimization, though. At some point we are going to bottleneck on the main thread or limits on parallel network requests. That limits how much of a win we can get with something like this.

@annevk
Copy link
Member

annevk commented Dec 16, 2016

Static routes would be the declarative solution, but I think at some point we want something on fetch() too. E.g., you might want to bypass foreign fetch and such.

@jakearchibald
Copy link
Contributor

Yeah, for the non-declarative solution we could expose the "use-service-workers" value that's in-progress.

@wanderview
Copy link
Member

My impression was that @n8schloss wanted to use this for network requests triggered by page elements, etc. So not sure adding a field to RequestInit is enough. (Although I think thats a good idea.)

@annevk
Copy link
Member

annevk commented Dec 16, 2016

Yeah, but just like referrerpolicy is on both, I could imagine service-workers mode to be on both in a similar manner.

@jakearchibald
Copy link
Contributor

But yeah, I think @n8schloss is looking for something declarative.

$TATIC ROUTEZ

@wanderview
Copy link
Member

Regarding the RequestInit or tag attribute, would that bypass foreign fetch SWs as well or only same-origin SWs? It seems a site could reason about their own SW implementation, but maybe not about what other origins are doing.

@annevk
Copy link
Member

annevk commented Dec 16, 2016

Depends on what granularity we offer. For specifications we need "none", "all", and "foreign" (only foreign service workers) thus far.

@annevk
Copy link
Member

annevk commented Dec 16, 2016

@jakearchibald declarative can also be <img serviceworker=foreign src=...>.

@n8schloss you wrote:

If we send 40 or so requests from the window at once, while the first few may be quick, the other events get tacked onto the end of the Service Worker event loop and end up getting delayed quite a bit before they can hit the network.

Did you measure this? This sounds extremely unlikely to be so slow as you suggest. Forty event loop turns should be super quick.

@wanderview
Copy link
Member

Did you measure this? This sounds extremely unlikely to be so slow as you suggest. Forty event loop turns should be super quick.

I expect a lot of this has to do with current implementation details. I believe networking has to go through the main thread in both firefox and chrome today. So after firing the SW FetchEvent you likely have to return to the main thread to start the actual network. This could be blocked on http parse, script, or anything else running there.

I'm sure this will improve over time, but one way to do that is to let the page give us precise information about intent so we can get the request to the right place with a minimum of main thread touches.

@n8schloss
Copy link
Author

n8schloss commented Dec 16, 2016

Did you measure this? This sounds extremely unlikely to be so slow as you suggest. Forty event loop turns should be super quick.

We did a number of measurements on this and there is currently significant overhead, plus even in a perfect world this can get blocked a lot on script. If I know that the SW isn't going to respond to a particular fetch event then having it get blocked at all on a SW is a waste.

Yeah, for the non-declarative solution we could expose the "use-service-workers" value that's in-progress.

That sounds amazing imo! Thinking about this more there will be times where we know far enough in advance that we should skip the SW so declarative routing will work. But other times it would make more sense to do it within fetch options. Both have real value and the more I think about it the more I feel like doing both is the right call.

@jakearchibald
Copy link
Contributor

F2F: I'd like to get an impression of how much of the slow here is "Chrome problems", I believe we get stuck on the main thread a bit with lots of requests.

@inian
Copy link

inian commented Mar 30, 2017

As I mentioned here, there is a lot of time spent in Chrome in routing to the service worker when there are a lot of requests - though I am not able to replicate this reliably.

@gs-akhan
Copy link

Hi,
In case of too many requests I have seen that "Request To Service Worker" time is too high compared to when we don't have service worker.

The delta is usually 500ms with and without.

Thanks

@jakearchibald
Copy link
Contributor

F2F: Adding service worker mode to fetch sounds easy. Exposing fetch options to various HTML elements is harder. We end up with lots of JSON in attributes. Good ideas needed.

@mangelozzi
Copy link

mangelozzi commented Feb 3, 2022

How about this to "bypass" the service worker:

async function handleFetch(event) {
    // Example to not cache: const init = { 'cache': 'reload' }; let response = await fetch(url, init);
    // A way to bypass the service worker
    if (event.request.cache === "reload") return
    event.respondWith(....);
}

Refer to the cache options here: https://developer.mozilla.org/en-US/docs/Web/API/fetch

@wanderview
Copy link
Member

FYI, the experiment facebook ran to try to bypass SW for unnecessary subresource requests did not yield a performance improvement:

#1584 (comment)

Just wanted to cross-link that here as a data point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants