@byungi/p-cancel-sagadeprecated

A cancelable promise with saga.

Usage no npm install needed!

<script type="module">
  import byungiPCancelSaga from 'https://cdn.skypack.dev/@byungi/p-cancel-saga';
</script>

README

@byungi/p-cancel-saga

A cancelable promise with saga.

Example

import pCancelSaga, { IS_CANCELED } from '@byungi/p-cancel-saga'

const promise = pCancelSaga(function * () {
    try {
        const result1 = yield async100msTask()
        console.log('The 1st task is done.')

        const result2 = yield async100msTask()
        console.log('The 2nd task is done.')

        return result2
    } finally {
        if (yield IS_CANCELED) {
            console.log('Canceled!')
        }
    }
})

delay(150).then(() => {
    promise.cancel()
    // => "The 1st task is done."
    // => "Canceled!"
    // (`The 2nd task is done.` is not print.)
})

API

pCancelSaga(saga)

Create a cancelable promise using a saga(generator). Similar to p-cancel but without the hassle of checking to cancel after asynchronous task.

Example

Before
const promise = new PCancel((resolve, reject, onCancel) => {
    onCancel(() => console.log('Canceled!'))

    async100msTask().then(result1 => {
        if (!promise.isCanceled) {
            console.log('The 1st task is done.')

            async100msTask().then(result2 => {
                if (!promise.isCanceled) {
                    console.log('The 2nd task is done.')
                    resolve(result2)
                }

            }).catch(reject)
        }
    }).catch(reject)
})
After
const promise = pCancelSaga(function * () {
    try {
        const result1 = yield async100msTask()
        console.log('The 1st task is done.')

        const result2 = yield async100msTask()
        console.log('The 2nd task is done.')

        return result2
    } finally {
        if (yield IS_CANCELED) {
            console.log('Canceled!')
        }
    }
})
Cancel propagation
const parentPromise = new PCancel((resolve, reject, onCancel) => {
    onCancel(() => {
        console.log('Cancel parent')
    })
    /* ... */
})

const childPromise = pCancelSaga(function * () {
    try {
        const result = yield parentPromise
        /* ... */
    } finally {
        if (yield IS_CANCELED) {
            console.log('Cancel child')
        }
    }
})

childPromise.cancel()
// => Cancel child
// => Cancel parent

promise.cancel([reason])

Stop the flow in saga and throw a CancelError to promise.

promise.isCanceled

Returns whether the promise is canceled.

promise.pipe(onFulfilled, onRejected)

Similar to then but can propagate cancel to the upper promise.

IS_CANCELED

yield this symbol in saga, it returns whether the promise is canceled.

factory(saga)

Returns a reusable function using saga with arguments.

import { factory, IS_CANCELED } from '@byungi/p-cancel-saga'

const asyncTaskFunction = factory(function * (url, params) {
    try {
        const result = yield apiGet(url, params)
        return result
    } finally {
        if (yield IS_CANCELED) {
            /* ... */
        }
    }
})

const promise = asyncTaskFunction('/data', { id: 1 })

silent(saga)

If it's just a cancelable task (not a promise), CancelError is bothersome. This function does not propagate an error.

import { silent, IS_CANCELED } from '@byungi/p-cancel-saga'

const task = silent(function * () {
    while (true) {
        yield delay(1000)
        yield asyncTask()
    }
})

task.cancel() // => No `unhandledRejection` occurs.

Tips

Type inference of yield promise in saga

const promise = pCancelSaga(function * () {
    const data = yield getDataAsync() // => "data" type is `any` or `unknown`.
    /* ... */
})

In TypeScript, type inference of yield promise in generator functions is difficult. Specify the type or use the provided helper type(AsyncResult<F>).

import pCancelSaga, { AsyncResult } from '@byungi/p-cancel-saga'

const promise = pCancelSaga(function * () {
    const data = (yield getDataAsync()) as {value: string}

    // or
    const data = (yield getDataAsync()) as AsyncResult<typeof getDataAsync>

    /* ... */
})

License

MIT