Timing out

Service worker strategies

Alright, so in my service worker script, I’ve got a block of code for handling requests from fetch events:

addEventListener('fetch', fetchEvent => {
const request = fetchEvent.request;
// Do something with this request.
});
if (request.headers.get('Accept').includes('text/html')) {
// Code for handling page requests.
}
if (request.headers.get('Accept').includes('text/html')) {
// Code for handling page requests.
} else {
// Code for handling everthing else.
}
fetchEvent.respondWith(
fetch(request)
.then( responseFromFetch => {
return responseFromFetch;
})
.catch( fetchError => {
return caches.match('/offline');
})
if (request.headers.get('Accept').includes('text/html')) {
fetchEvent.respondWith(
fetch(request)
.then( responseFromFetch => {
return responseFromFetch;
})
.catch( fetchError => {
return caches.match('/offline');
})
);
}
caches.match(request)
.then( responseFromCache => {
return responseFromCache || fetch(request);
})
addEventListener('fetch', fetchEvent => {
const request = fetchEvent.request;
if (request.headers.get('Accept').includes('text/html')) {
fetchEvent.respondWith(
fetch(request)
.then( responseFromFetch => {
return responseFromFetch;
})
.catch( fetchError => {
return caches.match('/offline');
})
);
} else {
caches.match(request)
.then( responseFromCache => {
return responseFromCache || fetch(request);
})
}
});

Cache as you go

Now I want to introduce an extra step in the part of the code where I deal with requests for pages. Whenever I fetch a page from the network, I’m going to take the opportunity to squirrel it away in a cache. I’m calling that cache “pages”. I’m imaginative like that.

fetchEvent.respondWith(
fetch(request)
.then( responseFromFetch => {
const copy = responseFromFetch.clone();
try {
fetchEvent.waitUntil(
caches.open('pages')
.then( pagesCache => {
return pagesCache.put(request, copy);
})
)
} catch(error) {
console.error(error);
}
return responseFromFetch;
})
const copy = responseFromFetch.clone();
fetchEvent.waitUntil(
caches.open('pages')
.then( pagesCache => {
return pagesCache.put(request, copy);
})
)
addEventListener('fetch', fetchEvent => {
const request = fetchEvent.request;
if (request.headers.get('Accept').includes('text/html')) {
fetchEvent.respondWith(
fetch(request)
.then( responseFromFetch => {
const copy = responseFromFetch.clone();
try {
fetchEvent.waitUntil(
caches.open('pages')
.then( pagesCache => {
return pagesCache.put(request, copy);
})
)
} catch(error) {
console.error(error);
}

return responseFromFetch;
})
.catch( fetchError => {
return caches.match('/offline');
})
);
} else {
caches.match(request)
.then( responseFromCache => {
return responseFromCache || fetch(request);
})
}
});
.catch( fetchError => {
return caches.match('/offline');
})
.catch( fetchError => {
caches.match(request)
.then( responseFromCache => {
return responseFromCache || caches.match('/offline');
})
});

Timing out

I want to throw this addition into my logic:

if (request.headers.get('Accept').includes('text/html')) {
fetchEvent.respondWith(
new Promise( resolveWithResponse => {
// Code for handling page requests.
})
);
}
addEventListener('fetch', fetchEvent => {
const request = fetchEvent.request;
if (request.headers.get('Accept').includes('text/html')) {
fetchEvent.respondWith(
new Promise( resolveWithResponse => {
fetch(request)
.then( responseFromFetch => {
const copy = responseFromFetch.clone();
try {
fetchEvent.waitUntil(
caches.open('pages')
then( pagesCache => {
return pagesCache.put(request, copy);
})
)
} catch(error) {
console.error(error);
}
resolveWithResponse(responseFromFetch);
})
.catch( fetchError => {
caches.match(request)
.then( responseFromCache => {
resolveWithResponse(
responseFromCache || caches.match('/offline')
);

})
})
})
);
} else {
caches.match(request)
.then( responseFromCache => {
return responseFromCache || fetch(request);
})
}
});
const timer = setTimeout( () => {
caches.match(request)
.then( responseFromCache => {
if (responseFromCache) {
resolveWithResponse(responseFromCache);
}
})
}, 3000);
clearTimeout(timer);
addEventListener('fetch', fetchEvent => {
const request = fetchEvent.request;
if (request.headers.get('Accept').includes('text/html')) {
fetchEvent.respondWith(
new Promise( resolveWithResponse => {
const timer = setTimeout( () => {
caches.match(request)
.then( responseFromCache => {
if (responseFromCache) {
resolveWithResponse(responseFromCache);
}
})
}, 3000);

fetch(request)
.then( responseFromFetch => {
clearTimeout(timer);
const copy = responseFromFetch.clone();
try {
fetchEvent.waitUntil(
caches.open('pages')
then( pagesCache => {
return pagesCache.put(request, copy);
})
)
} catch(error) {
console.error(error);
}
resolveWithResponse(responseFromFetch);
})
.catch( fetchError => {
clearTimeout(timer);
caches.match(request)
.then( responseFromCache => {
resolveWithResponse(
responseFromCache || caches.match('/offline')
);
})
})
})
);
} else {
caches.match(request)
.then( responseFromCache => {
return responseFromCache || fetch(request)
})
}
});

Pros and cons

As with all service worker enhancements to a website, this strategy will do absolutely nothing for first-time visitors. If you’ve never visited my site before, you’ve got nothing cached. But the more you return to the site, the more your cache is primed for speedy retrieval.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jeremy Keith

Jeremy Keith

A web developer and author living and working in Brighton, England. Everything I post on Medium is a copy — the originals are on my own website, adactio.com