- From: Jake Archibald <notifications@github.com>
- Date: Mon, 14 Mar 2016 07:13:52 -0700
- To: slightlyoff/ServiceWorker <ServiceWorker@noreply.github.com>
- Message-ID: <slightlyoff/ServiceWorker/issues/844/196324648@github.com>
> don't you want to go to cache even if the networkFetchPromise was thenable but respons.ok was false?
Sure thing. Probably want to avoid those going into the cache too…
```js
self.addEventListener('fetch', event => {
const cacheResponsePromise = caches.match(event.request);
const networkFetchPromise = fetch(event.request);
// # Populating the cache from the network
// WARNING: by adding all responses into the cache like this, you'll run out
// of space pretty quickly, you should restrict the URLs you do this for, or clean
// the cache at some points
event.waitUntil(
networkFetchPromise.then(response => {
// If the response wasn't ok, we're not interested
if (!response.ok) return;
// clone the response, because we're going to use it twice
const responseClone = response.clone();
return caches.open('my-cache-name')
.then(cache => cache.put(event.request, responseClone));
})
);
// # Responding to the request
event.respondWith(
// race the network and a timeout
Promise.race([
networkFetchPromise,
new Promise((_, reject) => {
setTimeout(() => reject(Error('Timeout')), 2000);
})
]).then(response => {
// Prefer the cache if the response is not ok
if (!response.ok) throw Error('Not ok');
return response;
// if this times out or rejects, see if the cache came up with anything…
}).catch(() => cacheResponsePromise).then(response => {
// if the cache has no match, defer to the network (without a timeout)
// Note: you didn't say you wanted this, but it seems to make sense,
// a slow network response is better than no response.
return response || networkFetchPromise;
})
);
});
```
> is the network-hit response delayed until after you've updated the cache?
It works the same as this http://jsbin.com/lidoda/edit?js,console. The first attached `then` executes first, but async actions within a `then` handler don't block other handlers on the same promise. I'm relying on the ordering for the response cloning.
> doesn't event.request have to be cloned in there somewhere?
It is, see `const responseClone = response.clone()`.
Although we're using a timeout, this approach still suffers from being online-first. A better approach is offline-first https://jakearchibald.com/2014/offline-cookbook/#cache-then-network
---
Reply to this email directly or view it on GitHub:
https://github.com/slightlyoff/ServiceWorker/issues/844#issuecomment-196324648
Received on Monday, 14 March 2016 14:14:21 UTC