5

with regards to this api https://developer.mozilla.org/en-US/docs/Web/API/Cache, I'd like to also set the cache lifetime.

let's say, cache this request for no longer than 10 minutes

Hitmands
  • 13,491
  • 4
  • 34
  • 69

3 Answers3

3

That is, unfortunately, not possible.

The doc you linked specifically states that items in the cache objects provided by the Cache API don't automatically get updated nor deleted. You have to implement that sort of logic on your own.

You should note that libraries eg. Workbox already does that for you. You could take advantage of that if other functionality suits your usecase.

https://developers.google.com/web/tools/workbox/

pate
  • 4,937
  • 1
  • 19
  • 25
  • With the Workbox setup, the expired service worker will still be shown once, but then `the plugin will check and remove entries after each request or cache update. Because it’s slow to open IndexedDB, expiration won’t occur until after the request is used. This means that an expired request may be used once, but will be expired after that.` So from my understanding this doesn't really set an expiry date on the service worker itself, but just refreshes afterwards. The relevant link is: https://developers.google.com/web/tools/workbox/modules/workbox-expiration. – fredrivett Mar 08 '22 at 10:53
2

This is how I implemented this without Workbox. (If you can switch to Workbox, please do, if not – keep reading)

  • Created a caching strategy which onFetchComplete clones the response from network, adds a timestamp header say x-sw-cache-timestamp.
  • store this cloned updated response to cache.
  • onCacheMatch compare the x-sw-cache-timestamp with currentTime and if exceeded the 10 min window, fetch from network.
function onFetchComplete(response) {
  var timestampHeader = {}
  timestampHeader['x-sw-cache-timestamp'] = Date.now()

  return serviceWorker
    .cloneResponse(response, timestampHeader)
    .then(function (responseCopy) {
      cache.add(request, responseCopy.clone())
      return responseCopy
    })
}

serviceWorker.cloneResponse = function (response, extraHeaders) {
  if (!response) {
    return serviceWorker.Promise.resolve()
  }

  var init = {
    status: response.status,
    statusText: response.statusText,
    headers: extraHeaders || {},
  }

  response.headers.forEach(function (val, key) {
    init.headers[key] = val
  })

  return response.blob().then(function (blob) {
    return new serviceWorker.Response(blob, init)
  })
}

Hope this helps!

firedev
  • 20,898
  • 20
  • 64
  • 94
puneetpr
  • 21
  • 2
1

You can dynamically create cache names that encode their creation time and max age, something simple like: ${dateStr}_${maxAgeMs}. Then when intercepting a fetch in your service worker you can look through the existing caches using caches.keys and find one that isn't expired using just its name and match against that, or create a new one if they're all expired and populate it with the incoming fetches. This also gives you an opportunity to delete the expired caches.

I needed to do this as well and took a look at the mentioned workbox project, seems like they're doing a similar thing with IndexedDB storage but that seems overkill for the ask.

TylerFowler
  • 568
  • 4
  • 8
  • I'd note though that the other solution of attaching a header (something I tried first but was put off by the idea of trying to manually make copies of a `Response` object) has the benefit of also allowing your main app to detect when it's being served one of these cached responses. – TylerFowler May 28 '19 at 02:03