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.
# promise retrying
2 min read
Take a function that creates a promise and retry it automatically if it fails. Memoize it to avoid duplicate instances.
# hold()
const pause = () =>
hold(1).then(n =>
console.log(`took ${n} seconds`)
)
function hold(n) {
return new Promise(resolve =>
setTimeout(resolve, n * 1000, n)
)
}
# makeCounter()
const { count, up } = makeCounter()
function makeCounter() {
let count = 0
return {
up: () => ++count,
count: () => count
}
}
# ResolveOnThirdTry()
const Log = x => y =>
console.log(...[x, y])
const run = ResolveOnThirdTry()
run()
.then(Log('resolved'))
.catch(Log('rejected'))
function ResolveOnThirdTry() {
let count = 0
return () =>
new Promise((resolve, reject) =>
hold(1).then(() => {
++count > 2
? resolve('ð')
: reject('ð§')
})
)
}
# makePromise()
const Log = msg => () => console.log(msg)
const [promise, resolve, reject] =
makePromise()
promise
.then(Log('then'))
.catch(Log('catch'))
.finally(Log('finally'))
function makePromise() {
let resolve
let reject
const promise = new Promise((O, X) => {
resolve = O
reject = X
})
return [promise, resolve, reject]
}
# RetryablePromise()
const fakeFetch = ResolveOnThirdTry()
const fetchWithRetries = RetryablePromise(
(retryCount, url) => fakeFetch(url)
)
const getUser = id =>
fetchWithRetries(3, `/user?id=${id}`)
.then(() => console.log('ð fetched'))
.catch(errors => {
console.log(`Too many retries.`)
console.log(`Saw: ${errors}`)
})
function RetryablePromise(fn) {
const firstTry = 0
return (maxRetries, ...args) => {
const [promise, resolve, reject] =
makePromise()
const errors = []
keepTrying(firstTry)
return promise
function keepTrying(retryCount) {
fn(retryCount, ...args)
.then(resolve)
.catch(error => {
const count = errors.push(error)
if (count >= maxRetries) {
return reject(errors)
}
keepTrying(count)
})
}
}
}
# RetryablePromise() + Memoize()
const getUser = Memoize((id, invalidate) => {
const user = fetchWithRetries(3, id)
user.catch(invalidate)
return user.then(() => {
console.log('ð fetched')
setTimeout(invalidate, seconds(7))
})
})
function Memoize(fn) {
const cache = new Map()
const Invalidater = x => () => {
cache.delete(x)
console.log('â cache invalidated')
}
return x =>
cache.has(x)
? cache.get(x)
: cache
.set(x, fn(x, Invalidater(x)))
.get(x)
}