在我工作的公司中,目前一切都是通过回调来完成的。我们开始用大代码所依赖的承诺编写小组件。我们开始遇到麻烦了。
function getSomething() {
return Promise.resolve('hello')
}
function test(cb) {
getSomething()
.then(string => {
a.s
cb(null, string)
}, error => cb(error))
}
test((error, result) => {
console.log(error)
console.log(result)
a.s
})
这是问题的一个简单示例。在此代码中,由于a不存在,它会抛出一个警告UnhandledPromiseRejectionWarning并终止该进程。永远不会达到控制台日志。
背后的逻辑是,如果发生错误,它将触发catch回调。
function test(cb) {
getSomething()
.then(string => {
// a.s
cb(null, string)
}, error => cb(error))
.catch(error => cb(error))
}
我被建议在promise链的末尾使用显式catch。问题是如果在回调中抛出错误,回调将触发两次。
感谢您的帮助。
答案 0 :(得分:1)
之间存在细微差别
.then(onFulfilled, onRejected)
和
.then(onFullfilled)
.catch(onRejected)
第一个将无法捕获onFullFilled
回调中抛出的错误,而第二个回调。因此,您可能不应该在当时阶段使用onRejected
回调,只需像在第二个代码段中那样链接.catch()
。
答案 1 :(得分:0)
您可以将then
部分中的代码分开,以便在调用 cb 之前的错误与 cb 中发生的错误区别对待。您可以返回字符串值,而不是在那里调用 cb ,以便可以在链式then
方法中使用它。在那里你可以使用成功和失败之间的切换。那样 cb 只会在那里被调用。
现在,如果通过调用 cb 发生错误,您可以使用最终.catch
来捕获它,但之后您不会再调用 cb ,但也许只输出一些东西,或者级联错误,或者做那些你想做的事情。
这是一个包含三个用例的演示:
then
function getSomething() {
return Promise.resolve('hello');
}
function test(testNo, cb) {
getSomething()
.then(string => {
if (testNo == 2) a.s;
return string; // don't call cb yet
})
.then(cb.bind(null, null), cb) // now call it -- mutually exclusive with error case
.catch(error => { // catch any errors not yet captured -- i.e. in cb
console.log('test ' + testNo + ': error occurred in success callback');
});
}
for (let testNo = 1; testNo <= 3; testNo++) {
test(testNo, (error, result) => {
if (error)
console.log('callback for test ' + testNo + ' error:', error.message);
else
console.log('callback for test ' + testNo + ' success:', result);
if (testNo == 3) a.s;
});
}
答案 2 :(得分:0)
您的代码段中发生的情况是,当catch()
内发生错误时,您会返回被拒绝的承诺。
而且由于你之后没有任何处理程序,这个被拒绝的承诺不会被处理,并且(幸运的是)会弹出。
你主要有两种方法来解决这个问题:
您可以在then()
方法之后添加另一个function test(cb) {
getSomething()
.then(string => {
a.s
cb(null, string)
})
.catch(e => cb) //this catch() handles whatever rejected promise
//comes out of then() or from the earlier promise
}
then()
在这个解决方案中,可能会发生这样的情况:如果在执行cb(null,string)时抛出错误,则会调用两次回调。在这种情况下,你需要在回调中使用一个保护来区分不同的错误代码,以确定它是来自getSomething()还是来自cb(null,string)。
或者您可以在function test(cb) {
getSomething()
.then(string => {
try{
a.s
cb(null, string)
} catch(e) {
if(e.message == "callback error" {
//do what you want to do to with a callback error
} else {
//do whatever you want to do with other errors from your catch block
}
}
}, error => cb(error))
}
处理程序中添加传统的try / catch-block,如下所示
Match match = Regex.Match("Puerto Rico 123", @"^.*?(?=\d)");
string text = match.Value;
在此解决方案中,您可以使用guard来区分catch块中的不同错误原因,并且只调用一次回调。但是,您需要另一种处理机制来处理错误。一个简单的可能性是默默地吞下新的错误,但这可能是一个糟糕的解决方案。
这就是异步编程的问题,因为在最终执行回调之前堆栈上下文丢失,所以不可能将错误冒泡到中央处理程序。
干杯, 菲利克斯