promise-swr
Version:
Caches a promise-returning function with a stale-while-revalidate strategy
73 lines (65 loc) • 2.38 kB
JavaScript
/**
* 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.
*
* @template {any[]} T Tuple of argument types for the wrapped function.
* @template K Type of the cache key.
* @template R Return type of the wrapped function.
* @param {(...args: T) => R | Promise<R>} fn The function to cache.
* @param {object} [options] The options.
* @param {Map<K, any>} [options.cache] The cache. Follows the `Map` interface.
* @param {number} [options.maxAge] The max time to cache any result in ms.
* @param {(...args: T) => K} [options.resolver] The key resolver function.
* @param {number} [options.revalidate] The max time to wait until revalidating.
* @returns {(...args: T) => Promise<R>} A function that caches `fn`.
*/
function pSwr(fn, options = {}) {
const {
cache = new Map(),
maxAge = Infinity,
resolver = (...args) => args[0],
revalidate = 0
} = options
return function (...args) {
const key = resolver(...args)
const cached = cache.get(key)
const keyAge =
!cached || cached.revalidating ? 0 : Date.now() - cached.timestamp
if (!cached || keyAge > maxAge) {
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
})
.catch(function () {
cache.delete(key)
})
} else if (keyAge > revalidate && !cached.revalidating) {
cached.revalidating = true
Promise.resolve(fn(...args))
.then(function (result) {
cached.data = Promise.resolve(result)
cached.timestamp = Date.now()
cached.revalidating = false
})
.catch(function () {
cached.revalidating = false
})
}
return cache.get(key).data
}
}
module.exports = pSwr