ðŸŠī\zansh.in\js

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)
}

Google it:

ðŸŒļ closures 🌚 currying 🌷 destructuring assignment ðŸŒŧ fetch 🌞 high-order function ðŸŒđ hoisting 💐 new Map ðŸŒļ pre-increment operator 🌚 Promise 🌷 setTimeout ðŸŒŧ spread rest