promise-swr
Version:
Caches a promise-returning function with a stale-while-revalidate strategy
91 lines (74 loc) • 2.57 kB
JavaScript
const debug = require('debug')('promise-swr')
/**
* Caches a promise-returning function with a stale-while-revalidate strategy.
*
* Every time the wrapper function is called, if there is no data in the cache
* or if the age of the data is too old, new data will be fetched and returned.
* If the age of the data is greater than the revalidation threshold but still
* valid, it will be returned and new data will be fetched in the background. If
* the data is below the revalidation threshold, it is fresh and is returned
* right away.
*
* @param {Function} fn The function to cache.
* @param {object} [options] The options.
* @param {Map} [options.cache] The storage. Must implement the `Map` interface.
* @param {number} [options.maxAge] The max time to cache any result in ms.
* @param {Function} [options.resolver] The key resolver function.
* @param {number} [options.revalidate] The max time to wait until revalidating.
* @returns {Function} The cached function.
*/
function pSwr(fn, options = {}) {
const {
cache = new Map(),
maxAge = Infinity,
resolver = (...args) => args[0],
revalidate = 0
} = options
return function (...args) {
debug('Function called')
const key = resolver(...args)
const cached = cache.get(key)
const keyAge = cached
? cached.revalidating
? 0
: Date.now() - cached.timestamp
: 0
if (!cached || keyAge > maxAge) {
debug(cached ? 'Cache expired' : 'Cache is empty')
const _cached = {
data: Promise.resolve(fn(...args)),
revalidating: true,
timestamp: Infinity
}
cache.set(key, _cached)
_cached.data
.then(function () {
_cached.timestamp = Date.now()
_cached.revalidating = false
debug('Cache set')
})
.catch(function (err) {
debug('Cache set failed: %s', err.message)
cache.delete(key)
})
} else if (keyAge > revalidate) {
debug('Cache is stale, revalidating')
cached.revalidating = true
Promise.resolve(fn(...args))
.then(function (result) {
cached.data = Promise.resolve(result)
cached.timestamp = Date.now()
cached.revalidating = false
debug('Cache revalidated')
})
.catch(function (err) {
debug('Cache revalidation failed: %s', err.message)
cached.revalidating = false
})
}
debug('Returning cached data')
return cache.get(key).data
}
}
module.exports = pSwr