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.
# cancelling promises
2 min read
Three ways of cancelling promises: Using Revokable functions, Promises, and AbortController.
# OneWaySwitch()
const { isOn, turnOff } = OneWaySwitch()
function OneWaySwitch() {
let on = true
return {
isOn: () => on,
turnOff: () => (on = false)
}
}
# makeRevocable()
const log = makeRevocable(console.log)
const revoke = log.revoke
const run = () => log('hello, world')
function makeRevocable(fn) {
let revoked = false
const revoke = () => (revoked = true)
const wrapper = (...args) => {
if (revoked) return
fn(...args)
}
wrapper.revoke = revoke
return wrapper
}
# hold()
const pause = () =>
hold(1).then(n =>
console.log(`took ${n} seconds`)
)
function hold(n) {
return new Promise(resolve =>
setTimeout(resolve, n * 1000, n)
)
}
# then(revokable)
const log = makeRevocable(console.log)
const revoke = log.revoke
function run() {
hold(1).then(() => {
log('hello, world')
})
}
# 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]
}
# cancelSignal Promise
const [cancelSignal, cancel] =
makePromise()
const pause = () =>
Promise.all([
hold(3, cancelSignal).then(Log('1')),
hold(1, cancelSignal).then(Log('2')),
hold(2, cancelSignal).then(Log('3'))
])
.then(Log('hello, world ð'))
.catch(console.log)
function hold(n, cancelSignal) {
return new Promise((O, X) => {
const id = setTimeout(O, n * 1000, n)
cancelSignal.then(() => {
clearTimeout(id)
X(new Error('Cancelled'))
})
})
}
# AbortController
const controller = new AbortController()
const cancel = () => controller.abort()
const { signal } = controller
const pause = () =>
Promise.all([
hold(3, signal).then(Log('1')),
hold(1, signal).then(Log('2')),
hold(2, signal).then(Log('3'))
])
.then(Log('hello, world ð'))
.catch(console.log)
function hold(n, signal) {
return new Promise((O, X) => {
const id = setTimeout(O, n * 1000, n)
signal.addEventListener(
'abort',
() => {
clearTimeout(id)
X(new Error('Cancelled'))
},
{ once: true }
)
})
}