Closed Bug 1273886 Opened 10 years ago Closed 10 years ago

Service Worker doesn't intercept fetch requests on first page load

Categories

(Core :: DOM: Service Workers, defect)

defect
Not set
normal

Tracking

()

RESOLVED INVALID

People

(Reporter: jsnajdr, Unassigned)

Details

Steps to reproduce: 1. Get the service worker app from this repo: https://github.com/jsnajdr/service-worker-demo 2. Run it in a static HTTP server on localhost and open it in the browser 3. Click on the "Fetch From Worker" button. Expected result: - the page installed and activated a service worker that returns a synthesized response to all "/test*" URLs. - the click handler performs a fetch("/test") request - therefore, the fetch should be intercepted by the service worker and return a SW response Actual result: - the fetch is not intercepted, goes to the server and returns a 404 response - only after I reload the page, the intercepting starts working. In this case, the worker is already active when the page is loaded. Tested in latest Firefox 49 nightly. It's interesting that Chrome 50 behaves the same way, so maybe it's a (very strange) feature of Service Workers. But the worker fired the "activate" event, and the "navigator.serviceWorker.ready" promise is fulfilled, so the requests should be intercepted, shouldn't they?
This is working as designed in the service worker spec. This is what happens: 1) First page load gets the document from the network. The page is not controlled by any service worker. 2) Page registers your service worker script. 3) The browser loads the service worker script and installs it in the background. 4) The scope now has an active worker, but your page is still not controlled. 5) The page performs a fetch(). 6) The fetch() is not intercepted because there is no service worker controlling the page. 7) Reload the page. 8) The page load is intercepted by the active service worker. 9) The newly loaded page is now controlled by a service worker. See navigator.serviceWorker.controller is set now. What you can do to work around this is to use the clients.claim() call in your service worker activate event handler: addEventListener('activate', function(evt) { evt.waitUntil(clients.claim()); }); Then in your main document you can listen for the 'controllerchange' event to know that the service worker is now controlling your document. function waitForControlled() { return new Promise(function(resolve, reject) { if (navigator.serviceWorker.controller) { resolve(); } navigator.serviceWorker.addEventListener('controllerchange', function onControllerChange() { navigator.serviceWorker.removeEventListener('controllerChange', onControllerChange); resolve(); }); }); } waitForControlled.then(function() { return fetch(urlToBeIntercepted); }); In any case, marking this closed for now since we're conforming to the spec. Please let me know if you have any further questions. Thanks!
Status: NEW → RESOLVED
Closed: 10 years ago
Resolution: --- → INVALID
(In reply to Ben Kelly [:bkelly] from comment #1) > In any case, marking this closed for now since we're conforming to the spec. > Please let me know if you have any further questions. Thanks! Thanks Ben for explaining this somewhat counterintuitive behavior. After I called clients.claim() and waited for the "controllerchange" event, my requests started to be intercepted as expected.
You need to log in before you can comment on or make changes to this bug.