Play with the controls to see how the code works. All code is present in the page, but some scrollback may be necessary to grok everything.
# memoizer / caching / invalidation
2 min read
If your function or promise is slow but predictable, wrap it in a memoizer to put it behind a cache.
# compute
function computeValue() {
return thatWasQuick()
}
function computeValueSlowly() {
return thisWillTakeAWhile()
}
# cache
const cache = new Map()
function getValue() {
return cache.has('ð')
? cache.get('ð')
: 'Yes, we have no ð'
}
function setFast() {
const value = computeValue()
cache.set('ð', value)
}
function setSlow() {
const value = computeValueSlowly()
cache.set('ð', value)
}
# Memoize()
const getValue = Memoize(key => {
if (key === 'fast') {
return computeValue()
}
if (key === 'slow') {
return computeValueSlowly()
}
})
function Memoize(fn) {
const cache = new Map()
return x =>
cache.has(x)
? cache.get(x)
: cache.set(x, fn(x)).get(x)
}
# Memoize() + invalidate
const getValue = Memoize(
(key, invalidate) => {
setTimeout(invalidate, seconds(3))
if (key === 'fast') {
return computeValue()
}
if (key === 'slow') {
return computeValueSlowly()
}
}
)
function Memoize(fn) {
const cache = new Map()
const Invalidater = x => () => {
cache.delete(x)
console.log(`â "${x}" invalidated`)
}
return x =>
cache.has(x)
? cache.get(x)
: cache
.set(x, fn(x, Invalidater(x)))
.get(x)
}
function seconds(n) {
return n * 1000
}
# Memoize() + Promise
const run = () =>
fakeFetch('ðĶ').then(console.log)
const runMemo = () =>
fetchMemo('ð').then(console.log)
const fetchMemo = Memoize(
(id, invalidate) =>
fakeFetch(id)
.then(res => {
setTimeout(invalidate, seconds(7))
return res
})
.catch(invalidate)
)
function fakeFetch(id) {
return new Promise(resolve =>
setTimeout(
resolve,
seconds(1),
`Hey, ${id}`
)
)
}