3

With service workers comes great flexibility and power, but also much responsibility... in terms of keeping the cache under control and not allowing it to grow unnecessarily.

Is there a way to determine the age of a cached item, i.e. the time it has been sitting in the cache, and purge cached items periodically based on age?

I'm thinking here about something along the following lines:

const RUNTIME = 'runtime-cache';

var getAgeOf = function (request) {
    return (*time since request was cached*);  // <-- but HOW?
};

var purgeRuntimeCache = function (threshold) {      
    caches.open(RUNTIME).then(function (cache) {
        cache.keys().then(function (keys) {
            keys.forEach(function (request, index, array) {
                cache.match(request).then(function (response) {
                    if (getAgeOf(request) > threshold) {
                        console.log('delete old resource from runtime cache: ' + request.url);
                        cache.delete(request);
                    }
                });
            });
        });
    });
};
drmrbrewer
  • 11,491
  • 21
  • 85
  • 181
  • @RobertRowntree thanks that gives some useful pointers. I've tried using `response.headers['date']` in my code snippet above (in the innermost level) but I just get `undefined`... am I doing something wrong? – drmrbrewer Nov 03 '17 at 20:25
  • @RobertRowntree it's also a problem for opaque responses, where you can't actually query the header to determine any date associated with it?? Need to store a custom "put into cache" date separately? – drmrbrewer Nov 03 '17 at 22:49

1 Answers1

3

The Workbox folks seems to be parsing the 'date' from the response's headers. They also assume the response to be fresh if the date is not available. Check their source for the cacheExpiration plugin over here. I guess one could also save the caching time to IndexedDB or Caches upon fetching the asset from the network for the first time (the asset url as a key for example).

While it's a good exercise to implement something like this by hand and dig into details, my gut says people should generally be better of by using a library to handle the SW. Workbox might be the best option.

Update:

I haven't tried this out myself but I don't see any reason this wouldn't work in practice.

  • Use something like idb-keyval to make it super simple to use the IndexedDB as a keyval store
  • Use importScript(point this to idb-keyval.min.js) to have it in the SW
  • When you cache something, use its URL (string) as the IDB key and Unix time as as a value
  • Later on, iterate through the cache items and compare them to the timestamps found in IDB; if too old, delte from the cache
pate
  • 4,937
  • 1
  • 19
  • 25
  • The problem with using `date` is that this information is not accessible for opaque resources (even though it's valid to cache them), for which see here: https://stackoverflow.com/a/39109790 ... and it seems that pretty much any js from a CDN is opaque so those will potentially stick around in your SW indefinitely even using workbox. When you say "could also save the caching time to IndexedDB or Caches upon fetching the asset"... how would this be done? It seems that this would be the most elegant solution... to be able to associate some metadata with the cached entry. – drmrbrewer Nov 06 '17 at 08:10
  • 1
    While `Date` isn't available in opaque responses, you can at least use IndexedDB to keep track of the time an opaque response was last added/read from the cache, and use that to trigger expiration. That's part of what Workbox does. – Jeff Posnick Nov 06 '17 at 18:41
  • Will it be the case that metadata stored in IndexedDB will persist as long as the corresponding resource in the SW cache? My concern is that an item in SW cache might become orphaned if its "date added" metadata in IndexedDB has been wiped. Is it a sensible approach to keep track of expiry times via IndexedDB, for a consistent (and flexible) approach, or dangerous for the reason mentioned above? – drmrbrewer Nov 06 '17 at 18:57
  • 1
    @drmrbrewer IndexedDB is a persistend data store. So the information stays there as long as you don't wipe it or the user doesn't specifically clear the site's cookies and whatnot. You should read IndexedDB docs from MDN :) – pate Nov 07 '17 at 04:28