I'm using a service worker on chrome to cache network responses. What I intend to do when a client requests a resource:
Check cache - If it exists, return from cache, but also send a request to server and update cache if file differs from the cached version. If cache does not have it, send a request for it to the server and then cache the response.
Here's my current code for doing the same:
self.addEventListener('fetch', function (event) {
var requestURL = new URL(event.request.url);
var freshResource = fetch(event.request).then(function (response) {
if (response.ok && requestURL.origin === location.origin) {
// All good? Update the cache with the network response
caches.open(CACHE_NAME).then(function (cache) {
cache.put(event.request, response);
});
}
// Return the clone as the response would be consumed while caching it
return response.clone();
});
var cachedResource = caches.open(CACHE_NAME).then(function (cache) {
return cache.match(event.request);
});
event.respondWith(cachedResource.catch(function () {
return freshResource;
}));
});
This code does not work as it throws an error:
The FetchEvent for url resulted in a network error response: an object that was not a Response was passed to respondWith().
Can anyone point me in the right direction?
I'm using a service worker on chrome to cache network responses. What I intend to do when a client requests a resource:
Check cache - If it exists, return from cache, but also send a request to server and update cache if file differs from the cached version. If cache does not have it, send a request for it to the server and then cache the response.
Here's my current code for doing the same:
self.addEventListener('fetch', function (event) {
var requestURL = new URL(event.request.url);
var freshResource = fetch(event.request).then(function (response) {
if (response.ok && requestURL.origin === location.origin) {
// All good? Update the cache with the network response
caches.open(CACHE_NAME).then(function (cache) {
cache.put(event.request, response);
});
}
// Return the clone as the response would be consumed while caching it
return response.clone();
});
var cachedResource = caches.open(CACHE_NAME).then(function (cache) {
return cache.match(event.request);
});
event.respondWith(cachedResource.catch(function () {
return freshResource;
}));
});
This code does not work as it throws an error:
The FetchEvent for url resulted in a network error response: an object that was not a Response was passed to respondWith().
Can anyone point me in the right direction?
Share Improve this question asked Sep 7, 2016 at 7:39 AwolAwol 3532 silver badges13 bronze badges 5-
2
catch
actually returns a Promise object. you might want to attach athen
handler tocachedResource
and callrespondWith
within that – thefourtheye Commented Sep 7, 2016 at 7:41 -
@thefourtheye - Don't you mean, call
event.respondWith
insidethen
forcache.match
? That will be an error, since fetch will be resolved by the timecaches.open
is executed. I made the change and ran the code to find this error. – Awol Commented Sep 7, 2016 at 7:47 - @Awol: How so? Presumably the cache opens and matches faster than the fetch? – Bergi Commented Sep 7, 2016 at 10:17
-
@Bergi - Fetch sure takes more time than the cache open, but
event.respondWith
is fired insidecaches.open
, which is triggered much later after thefetch
handler ends – Awol Commented Sep 7, 2016 at 10:22 - Okay, guys. I fixed my issue and posted the answer. Thank you so much for the ideas! – Awol Commented Sep 7, 2016 at 10:28
1 Answer
Reset to default 7Okay, I fiddled with the code after people pointed out suggestions (thank you for that) and found a solution.
self.addEventListener('fetch', function (event) {
var requestURL = new URL(event.request.url);
var freshResource = fetch(event.request).then(function (response) {
var clonedResponse = response.clone();
// Don't update the cache with error pages!
if (response.ok) {
// All good? Update the cache with the network response
caches.open(CACHE_NAME).then(function (cache) {
cache.put(event.request, clonedResponse);
});
}
return response;
});
var cachedResource = caches.open(CACHE_NAME).then(function (cache) {
return cache.match(event.request).then(function(response) {
return response || freshResource;
});
}).catch(function (e) {
return freshResource;
});
event.respondWith(cachedResource);
});
The entire problem originated in the case where the item is not present in cache and cache.match
returned an error. All I needed to do was fetch actual network response in that case (Notice return response || freshResource
)
This answer was the Aha!
moment for me (although the implementation is different):
Use ServiceWorker cache only when offline