假设我有4个功能:runA()
,runB()
,runC()
和runD()
。
使用ES6承诺,在完全成功的运行中,这些都将一个接一个地运行:
runA()
.then(runB)
.then(runC)
.then(runD)
如果runA
或runB
失败(拒绝或抛出),我想致电error1()
,然后完全停止连锁(不是致电runC
或{{1 })。这让我觉得我应该在runD
承诺链的最后添加一个.catch()
:
.then
但如果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)
失败,我想致电runC
并仍然停止连锁(不是致电error2()
)。
runD
现在我在链中有2 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)
个调用,catch
将在runC
运行后被调用,因为catch的结果将默认为error1
。我唯一的选择是让resolve
函数创建一个总是拒绝的承诺吗?
答案 0 :(得分:4)
不,让error1
创建一个始终拒绝的承诺, 不 是您唯一的选择。
你可以利用.then
有两个参数的事实:
.then(onSuccess, onFailure)
如果给出两个参数,那么onFailure
会在onSuccess
中捕获失败,效果不佳。这通常是不受欢迎的,除了在这里,您可以使用此事实来分支您的决策树:
runA()
.then(runB)
.then(() => runC().then(runD), error1)
.catch(error2)
这就是你想要的。
runA
或runB
失败,则调用error1
并停止链接。runC
或runD
失败,则调用error2
并停止链接。您也可以这样写:
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)
&#13;
<div id="div"></div>
&#13;
尝试修改this fiddle中的哪一个失败。
答案 1 :(得分:1)
仅使用一个.catch()
有什么问题?您可以在catch回调(if (error1) error1() else if (error2) error2()...
)中进行错误分类。您抛出的Error
对象可以包含一条消息和一个名称(可能是您需要的类型,例如,RunCError&#39;)。
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...
}
答案 2 :(得分:0)
我只是偶然发现了同样的问题,到目前为止我的解决方案是明确调用{j} bin中的reject
中的catch
:https://jsbin.com/yaqicikaza/edit?js,console
代码段
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
&#13;