Handle Cancellations in finally blocks?
See original GitHub issueActually, cancellations are thrown as exceptions inside cancelled tasks.
function* saga() {
try {
const result = yield call(api)
yield put(successAction(result))
} catch(err) {
if(!isCancelError(err))
yield put(errorAction(err))
}
}
The check isCancelError
is always necessary, even if we aren’t interested in handling cancellations. Otherwise the saga will put an errorAction
even is this is only a cancellation and not an api error. In practice I noticed that handling cancellations is pretty rare (most of the time we do nothing). While handling errors is more common.
Also cancellations do not have the same semantics as errors; Errors are values bubbling up from callees to callers, while cancellations are much like ‘forced values’ which propagate down from callers to callees.
My question is would it make more sense, and also would it be preferable to handle cancellations in finally blocs instead of catch blocks.
So for example we can write the previous example as
function* saga() {
try {
const result = yield call(api)
yield put(successAction(result))
} catch(err) {
yield put(errorAction(err))
}
}
There is no need to isCancelError
since the saga is not interested in handling the cancellation. Alternatively a saga that needs some special actions when it is cancelled could be written like this
function* saga() {
try {
const result = yield call(api)
yield put(successAction(result))
} catch(err) {
yield put(errorAction(err))
} finally {
if( (yield status()) === CANCELLED)
// handle cancellations
}
}
Since finally blocks do not accept arguments, we’ll need to provide some way to check that w’ve been cancelled (finally will execute in 3 cases: normal return, unhandled error or ‘forced return’ i.e. cancellation). Above we use a yield status()
effect.
It may look more awkward than the check inside catch, but I think the uses for this would be pretty rare (compared to catch usage)
I’ve almost implemented all new changes in the project (channels, support SSR, attached forks …); So far this is the only one concern left before making the next release and I’m not able to decide on it
Issue Analytics
- State:
- Created 7 years ago
- Reactions:3
- Comments:8 (5 by maintainers)
Top GitHub Comments
@elliottsj To simulate cancellation call
gen.return()
. If the saga asks for the cancel status with ayield cancelled()
resume it with true@bradennapier I guess I am a bit late, but - just in case you haven’t bothered to find the answer later on - here is what happens: The javascript
finally
block is special because it gets executed not just every time when the code intry
block succeeds or fails, but it is also called even if the code in try succeeds and there is areturn
statement there. However, any additional code after thetry.catch.finally
is not executed if thereturn
is executed beforehand.Now, the generators work pretty much the same, except that the return is called on the iterator.