我很确信我误解了承诺是如何运作的,但很多人都有阅读未能解决我的问题。
我有现有的代码调用另一个刚刚更改为使用promises的模块。使用旧版本看起来像这样:
function(params, cb) {
.....
asyncFunc(p1, (err, res) => {
if (!err)
.....
cb(null,'msg');
else
cb(err);
};
};
将此更改为:
function(params, cb) {
.....
asyncFuncwithPromise(p1).then(res = > {
... // X
return cb(null,'msg');
}).catch(err => {
cb(err);
});
如果X行的代码抛出异常,则会进入catch() - > then()的无限循环。从catch中删除回调,一切都很好。谁能解释一下?
答案 0 :(得分:0)
除非cb()
正在调用asyncFuncWithPromise()
,否则无法确定如何在此处创建无限循环。
我喜欢将Promise回调链视为两条平行轨道。要继续取消成功(then()
)跟踪,请使用return
关键字。要继续关注失败(catch()
)跟踪,请使用throw
关键字。链的轨道可以随时切换,但回调只能线性执行;也就是说,先前在链中定义的回调在稍后定义之后不能执行。链条总是向前推进,无法进入循环。
Promise.resolve()
.then(()=>{ // 1S
if (Math.floor(Math.random() * 2))
return "success"; // continue down "success" (then) track
else
throw "fail"; // continue down "failure" (catch) track
})
.then(r=>{ // 2S
return "all good: " + r;
})
.catch(e=>{ // 2F
// use 'return' to recover, continue down "success" track
return "recovered from error: " + e;
})
.then(r=>{ // 3S
console.log(r); // always executed
})
.catch(e=> { //3F
console.error(e); // never executed
});
在此示例中,将始终执行包含console.log()
的链中的最终成功链接(3S),因为catch()
链接(2F)使用return
来重新启用链成功之路。当然,如果每个链接都使用throw
关键字,则可以对多个链接执行失败跟踪。
使用Promise
构造函数创建新Promise时,成功和失败跟踪最初对应于解析程序中提供的resolve
和reject
函数。所以,这之间没有区别(功能上):
function getPromise(...) {
return new Promise((resolve, reject)=>{
/* do something... */
if (condition) {
resolve(result);
} else {
reject(error);
}
});
}
和此:
function getPromise(...) {
return Promise.resolve().then(()=>{
/* do something... */
if (condition)
return result;
else
throw error;
});
}
这些之间的差异巧妙地与Promise链中的链接如何遵循运行时事件框架有关。这可能因实现而异,但通常会将then()
或catch()
回调推迟到执行帧的下一个后继者。