Say I have 4 functions: runA()
, runB()
, runC()
and runD()
.
Using ES6 promises, in a pletely successful run, these would all be run one after another:
runA()
.then(runB)
.then(runC)
.then(runD)
If runA
or runB
fail (reject or throw), I would like to call error1()
and then pletely stop the chain (not call runC
or runD
). This makes me think I should add a single .catch()
at the very end of the .then
promise chain:
runA()
.then(runB)
.then(runC) //won't get called if runA or runB throws
.then(runD) //won't get called if runA or runB throws
.catch(error1)
But if runC
fails, I would like to call error2()
and still stop the chain (not call runD
).
runA()
.then(runB)
.catch(error1) //moved up to only handle runA and runB
.then(runC) //but now this gets called after error1() is run
.then(runD)
.catch(error2)
Now that I have 2 catch
calls in the chain, runC
will get called after error1
is run since the result of the catch will default to a resolve
. Is my only option to have the error1
function create a promise that it always rejects?
Say I have 4 functions: runA()
, runB()
, runC()
and runD()
.
Using ES6 promises, in a pletely successful run, these would all be run one after another:
runA()
.then(runB)
.then(runC)
.then(runD)
If runA
or runB
fail (reject or throw), I would like to call error1()
and then pletely stop the chain (not call runC
or runD
). This makes me think I should add a single .catch()
at the very end of the .then
promise chain:
runA()
.then(runB)
.then(runC) //won't get called if runA or runB throws
.then(runD) //won't get called if runA or runB throws
.catch(error1)
But if runC
fails, I would like to call error2()
and still stop the chain (not call runD
).
runA()
.then(runB)
.catch(error1) //moved up to only handle runA and runB
.then(runC) //but now this gets called after error1() is run
.then(runD)
.catch(error2)
Now that I have 2 catch
calls in the chain, runC
will get called after error1
is run since the result of the catch will default to a resolve
. Is my only option to have the error1
function create a promise that it always rejects?
-
What's wrong with using only one
.catch()
? You can do error triage in the catch callback (if (error1) error1() else if (error2) error2()...
). TheError
object you throw can have a message and a name (could be the type like you need, 'RunCError' for example). – Shanoor Commented Dec 24, 2015 at 7:29 -
of course, you meant
runA() .then(runB) .then(runC) .then(runD)
- ... other than that, if you really can not determine what caused the error, you canthrow
at the end oferror1
to skip pastrunC
andrunD
- but you'll need to determine inerror2
that the error came from A or B rather than C or D anyway – Jaromanda X Commented Dec 24, 2015 at 8:04
3 Answers
Reset to default 4No, having error1
create a promise that always rejects, is not your only option.
You can exploit the fact that .then
takes two arguments:
.then(onSuccess, onFailure)
When given two arguments, there's an under-appreciated effect that onFailure
will not catch failures in onSuccess
. This is usually undesirable, except here, where you can use this fact to branch your decision tree:
runA()
.then(runB)
.then(() => runC().then(runD), error1)
.catch(error2)
This does what you want.
- if
runA
orrunB
fail, thenerror1
is called and chain stops. - if
runC
orrunD
fail, thenerror2
is called and chain stops.
You can also write it like this:
runA()
.then(runB)
.then(() => runC()
.then(runD)
.catch(error2),
error1)
var log = msg => div.innerHTML += "<br>" + msg;
// Change which one of these four rejects, to see behavior:
var runA = () => Promise.resolve().then(() => log("a"));
var runB = () => Promise.reject().then(() => log("b"));
var runC = () => Promise.resolve().then(() => log("c"));
var runD = () => Promise.resolve().then(() => log("d"));
var error1 = () => log("error1");
var error2 = () => log("error2");
runA()
.then(runB)
.then(() => runC().then(runD), error1)
.catch(error2)
<div id="div"></div>
Try modifying which one fails in this fiddle.
What's wrong with using only one .catch()
? You can do error triage in the catch callback (if (error1) error1() else if (error2) error2()...
). The Error
object you throw can have a message and a name (could be the type like you need, 'RunCError' for example).
runA()
.then(runB)
.then(runC) // won't get called if runA or runB throws
.then(runD) // won't get called if runA or runB throws
.catch(handleErrors)
function runA() {
// ...
if (err) {
var error = new Error('Something is wrong...');
error.name = 'RunAError';
throw error;
}
}
function runB() {
// ...
if (err) {
var error = new Error('Something is wrong...');
error.name = 'RunBError';
throw error;
}
}
function runC() {
// ...
if (err) {
var error = new Error('Something is wrong...');
error.name = 'RunCError';
throw error;
}
}
function runD() {
// ...
if (err) {
var error = new Error('Something is wrong...');
error.name = 'RunDError';
throw error;
}
}
function handleErrors(err) {
if (err.name == 'RunAError') {
handleAError();
}
if (err.name == 'RunBError') {
handleBError();
}
// so on...
}
I just stumbled on the same problem and my solution is so far to explicitly invoke a reject
in a catch
like in this js bin: https://jsbin./yaqicikaza/edit?js,console
Code snippet
const promise1 = new Promise( ( resolve, reject ) => reject( 42 ) );
promise1
.catch( ( err ) => console.log( err ) ) // 42 will be thrown here
.then( ( res ) => console.log( 'will execute' ) ) // then branch will execute
const promise2 = new Promise( ( resolve, reject ) => reject( 42 ) );
promise2
.catch( ( err ) => Promise.reject( ) ) // trigger rejection down the line
.then( ( res ) => console.log( 'will not execute' ) ) // this will be skipped
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745325477a4622635.html
评论列表(0条)