15
loading...
This website collects cookies to deliver better user experience
function memoPromise(asyncFn, expiresIn) {
const memo = {}
const statusMap = {}
const resolves = []
const rejects = []
return async function memoizedFn(...args) {
if (args.length === 0) {
throw new Error(
"Must provide at least one serializable argument to generate an unique cache key"
)
}
const memoKey = args.toString()
if (memo[memoKey]) {
return Promise.resolve(memo[memoKey]())
}
if (statusMap[memoKey] === "pending") {
return new Promise((_res, _rej) => {
resolves.push(_res)
rejects.push(_rej)
})
}
try {
statusMap[memoKey] = "pending"
const result = await asyncFn(...args)
statusMap[memoKey] = "success"
memo[memoKey] = function get() {
if (typeof expiresIn === "number" && expiresIn > 0) {
setTimeout(() => {
memo[memoKey] = null
statusMap[memoKey] = null
}, expiresIn)
}
return result
}
resolves.forEach(res => res(result))
} catch (err) {
statusMap[memoKey] = "error"
rejects.forEach(rej => rej(err))
throw err
}
return memo[memoKey]()
}
}
memoPromise
is a higher order function that receives a promise-returning function and returns a new function. If we call the new function multiple times simultaneously, the calls after the first one will return a promise that resolves the result fetched by the first call, or rejects if the first call fails.expire
number to invalidate the memoized result after some time.memoPromise
to use and make a memoized fetch
that invalidate the result after 5 seconds:// utils.js
export const memoizedFetch = memoPromise(fetch, 5000)
// component 1
import { memoizedFetch } from './utils'
const result1 = await memoizedFetch('https://fakeapi.com/end-point').then(res => res.json())
// component 2
import { memoizedFetch } from './utils'
const result2 = await memoizedFetch('https://fakeapi.com/end-point').then(res => res.json())
15