Skip to content

Instantly share code, notes, and snippets.

@danwoods
Last active December 8, 2015 00:12
Show Gist options
  • Save danwoods/4dc19d744b753adce7a2 to your computer and use it in GitHub Desktop.
Save danwoods/4dc19d744b753adce7a2 to your computer and use it in GitHub Desktop.
this.addEventListener("fetch", function(event) {
console.log('WORKER: fetch event in progress.');
/* We should only cache GET requests, and deal with the rest of method in the
client-side, by handling failed POST,PUT,PATCH,etc. requests.
*/
if (event.request.url !== 'https://myserver.ngrok.com/app.js') {
/* If we don't block the event as shown below, then the request will go to
the network as usual.
*/
console.log('WORKER: fetch event ignored.', event.request.method, event.request.url);
return fetch(event.request);
}
/* Similar to event.waitUntil in that it blocks the fetch event on a promise.
Fulfillment result will be used as the response, and rejection will end in a
HTTP response indicating failure.
*/
event.respondWith(
caches
/* This method returns a promise that resolves to a cache entry matching
the request. Once the promise is settled, we can then provide a response
to the fetch request.
*/
.match(event.request)
.then(function(cached) {
/* Even if the response is in our cache, we go to the network as well.
This pattern is known for producing "eventually fresh" responses,
where we return cached responses immediately, and meanwhile pull
a network response and store that in the cache.
Read more:
https://ponyfoo.com/articles/progressive-networking-serviceworker
*/
var networked = fetch(event.request)
// We handle the network request with success and failure scenarios.
.then(fetchedFromNetwork, unableToResolve)
// We should catch errors on the fetchedFromNetwork handler as well.
.catch(unableToResolve);
/* We return the cached response immediately if there is one, and fall
back to waiting on the network as usual.
*/
console.log('WORKER: fetch event', cached ? '(cached)' : '(network)', event.request.url);
return cached || networked;
function fetchedFromNetwork(response) {
/* We copy the response before replying to the network request.
This is the response that will be stored on the ServiceWorker cache.
*/
var cacheCopy = response.clone();
console.log('WORKER: fetch response from network.', event.request.url);
caches
// We open a cache to store the response for this request.
.open(version + 'pages')
.then(function add(cache) {
/* We store the response for this request. It'll later become
available to caches.match(event.request) calls, when looking
for cached responses.
*/
cache.put(event.request, cacheCopy);
})
.then(function() {
console.log('WORKER: fetch response stored in cache.', event.request.url);
});
// Return the response so that the promise is settled in fulfillment.
return response;
}
/* When this method is called, it means we were unable to produce a response
from either the cache or the network. This is our opportunity to produce
a meaningful response even when all else fails. It's the last chance, so
you probably want to display a "Service Unavailable" view or a generic
error response.
*/
function unableToResolve () {
/* There's a couple of things we can do here.
- Test the Accept header and then return one of the `offlineFundamentals`
e.g: `return caches.match('/some/cached/image.png')`
- You should also consider the origin. It's easier to decide what
"unavailable" means for requests against your origins than for requests
against a third party, such as an ad provider.
- Generate a Response programmaticaly, as shown below, and return that.
*/
console.log('WORKER: fetch request failed in both cache and network.');
/* Here we're creating a response programmatically. The first parameter is the
response body, and the second one defines the options for the response.
*/
return new Response('<h1>Service Unavailable</h1>', {
status: 503,
statusText: 'Service Unavailable',
headers: new Headers({
'Content-Type': 'text/html'
})
});
}
})
);
});
@jeffposnick
Copy link

What's the request URL (including URL parameters) that you're using when you see the unexpected behavior?

Your fetch handler will exit early with return fetch(event.request); unless your request URL is "https://myserver.ngrok.com/app.js", but that seems odd. If you want to exit early and fall back to the default network behavior without any service worker involvement, you should just use return;. The return value of the fetch handler is ignored, and that extra fetch(event.request); is effectively doing nothing, except maybe resulting in extra, confusing log statements in your Network panel.

@danwoods
Copy link
Author

danwoods commented Dec 7, 2015

@jeffposnick The requested url I'm seeing the issue with (among others) is the /person/model one I've shown in the images, but the issue happens with any URL that's authenticated with headers.

I've changed the fetch function to return undefined as opposed to a fetch of the resource, and am still seeing the extra call. I even see it when I remove the fetch handler. You're saying this implies that there's an extra service worker somewhere trying to handle the fetch that I'm unaware of? When I look at chrome://inspect/#service-workers I only see the one I'm expecting, when I look at chrome://serviceworker-internals I see the worker I'm expecting plus an additional redundant worker that's stopped...

@danwoods
Copy link
Author

danwoods commented Dec 7, 2015

selection_182

selection_183

selection_184

selection_185

@danwoods
Copy link
Author

danwoods commented Dec 7, 2015

@jeffposnick I'm hoping those images will spur an "ah-ha!" moment :)

It feels like I'm having the same issue as this user http://stackoverflow.com/a/33836695/3896422

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