I’m writing a multi-step async sequence that involves different possible errors at each step. I want to abort the whole sequence if an error occurs.
I am trying to express this as a linear sequence using Promise.then()
and Promise.catch()
. Here is the pseudocode:
step1()
.catch(errorAtStep1 => handlerErrorAtStep1)
.then(resultOfStep1 => step2(resultOfStep1))
.catch(errorAtStep2 => handlerErrorAtStep2)
.then(resultOfStep2 => step3(resultOfStep2))
...
I understand that I need to throw something in each error handler to avoid getting back into the then(result)
parts. When I throw, though, the execution ends up in the next catch(error)
block, which was expecting an error that’s related to its corresponding step, not that other thing that I threw.
My question is: what are clean ways to handle this, that would minimize distraction when reading the code?
I came up with this class:
class AbortChainError extends Error {
static chain(handler) {
return function(error) {
if (error instanceof AbortChainError) throw error
handler(error)
throw new AbortChainError()
}
}
}
that allows the catch()
blocks to be written as:
.catch(AbortChainError.chain(errorAtStep2 => handlerErrorAtStep2))
with the additional need to write a final, empty catch()
block at the end of the sequence.
Can we do better?