Abort In COroutines (promise)
Inspired by Redux-Saga's Task cancellation, aico is designed to make promise cancellation simpler and more efficient. With a minimalist API, it integrates seamlessly with AbortController and TypeScript.
(Title inspired by the Netflix series A.I.C.O on Netflix))
import { aico } from 'aico'
const promise = aico(function* (signal) {
try {
yield fetch('/delay/100', { signal }) // <= This api takes 100ms.
console.log('1. This is printed.')
yield fetch('/delay/100', { signal }) // <= This api takes 100ms.
console.log('2. This is not printed.')
} finally {
if (signal.aborted) {
console.log('3. aborted!')
}
}
})
promise.catch(err => {
console.log(`4. message: ${err.name}`)
console.log(`5. isAborted: ${err.isAborted}`)
})
setTimeout(() => {
promise.abort() // <= After 150ms
}, 150)
> output
1. This is printed.
3. aborted!
4. message: AbortError
5. isAborted: true
npm install aico
Creates an abortable promise. Within the generator function, the yield
statement behaves like await
in an async function.
import { AbortInCoroutines } from 'aico'
const promise = new AbortInCoroutines(function* (signal) {
const result = yield Promise.resolve('hello')
return result
})
signal
parameter is AbortSignal that can cancel DOM requests such as fetch.
const promise = new AbortInCoroutines(function* (signal) {
const response = yield fetch('/api/request', { signal })
// ...
})
promise.abort() // <= Abort `/api/request` request.
signal
has an aborted
property that indicates whether the promise was aborted or not.
const promise = new AbortInCoroutines(function* (signal) {
try {
/* ... */
} finally {
if (signal.aborted) {
console.log('aborted!')
}
}
})
promise.abort() // => "aborted!"
If the yielded promise was created with AbortInCoroutines
, the cancellation is propagated.
const subTask = () =>
new AbortInCoroutines(function* (signal) {
try {
/* ... */
} finally {
if (signal.aborted) {
console.log('subTask is aborted!')
}
}
})
const promise = new AbortInCoroutines(function* () {
yield subTask()
})
promise.abort() // => "subTask is aborted!"
Allows for aborting the promise using an external AbortController signal.
const controller = new AbortController()
const promise = new AbortInCoroutines(
function* (signal) {
/* ... */
},
{
signal: controller.signal,
},
)
controller.abort()
If set to true
, an unhandledRejection occurs. Default is false
.
new AbortInCoroutines(
function* () {
/* ... */
},
{
unhandledRejection: true,
},
).abort()
Checks if the promise has been aborted.
console.log(promise.isAborted) // => false
promise.abort()
console.log(promise.isAborted) // => true
Abort the promise manually.
A shorthand function as an alternative to new AbortInCoroutines()
.
import { aico } from 'aico'
const promise = aico(function* (signal) {
/* ... */
})
An abortable version of Promise.all()
. If one promise rejects, all other promises are automatically aborted.
An abortable version of Promise.race()
. If one promise rejects, all other promises are automatically aborted.
An abortable version of Promise.any()
.
An abortable version of Promise.allSettled()
.
When working with TypeScript, you may find type inference challenging for yielded promises.
import { aico, cast } from 'aico'
const promise = aico(function* () {
const data = (yield fetchData()) as { value: string }
// or
const data = (yield fetchData()) as Awaited<ReturnType<typeof fetchData>>
})
Use cast
for better type inference.
import { aico, cast } from 'aico'
const promise = aico(function* () {
const data = yield* cast(fetchData())
})
MIT Β© skt-t1-byungi