2017-01-13 55 views
0

在我工作的公司里,一切都是用回调完成的。我们正在开始编写具有大代码所依赖的承诺的小组件。我们开始遇到麻烦。如何用回调包装承诺?

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)) 
} 

我被建议在承诺链的末尾使用显式捕获。问题是如果在回调中抛出一个错误,回调会触发两次。

感谢您的任何帮助。

+0

如何整个包住再放入一试,并在catch错误? –

+1

那么..那么可能你不应该在'then'阶段使用'onRejected'回调,而只需链接一个'.catch()'就像你在第二个代码段中做的那样。 – Redu

+0

@Redu,将此评论移至答案,因为这是正确的答案。 @ AlvaroOrtiz的第二段代码将错误处理程序'cb'连接两次。 – DaveS

回答

1

.then(onFulfilled, onRejected) 

.then(onFullfilled) 
.catch(onRejected) 

之间细微的差别第一个将无法赶上onFullFilled回调,而第二个会中抛出的错误。所以可能你不应该在当时的阶段使用onRejected回调,而只是像你在第二个片段中那样链接.catch()

+0

即使我删除'then'中的第二个处理程序并且发生错误,它仍然会再次在catch语句中调用处理程序。 –

+0

@Alvaro Ortiz这很正常。 '.catch()'函子是下游的,它会捕获前一阶段抛出的第一个错误。 – Redu

0

你可以让调用CB前误差比CB内发生的那些区别对待的代码在then部分分开。不要在那里调用cb,而是返回字符串值,以便可以在链接的then方法中使用它。在那里你可以使用成功和失败之间的切换。那样只会在那里调用cb

现在,如果通过调用CB发生错误时,你能赶上与最终.catch,但你不会把CB了,但也许只是输出一些东西,或级联错误,或做任何你想在这种情况下做。

这里有三个使用案例演示:

  1. 没有错误
  2. 在(第一)错误then
  3. CB

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; 
 
    }); 
 
}
错误

0

在您的代码片段中会发生什么情况:当您的then()中发生错误时,返回被拒绝的承诺。 因为在此之后你还没有任何处理程序,这个被拒绝的承诺不会被处理,并且(幸运的是)会弹出。

你主要有两种方法可以解决这个问题: 您既可以添加其他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 
} 

在该方案中,可能发生之后,你被调用两次回调的情况下,执行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)) 
} 

在此方案中您then()处理程序中添加一个传统的try/catch块,你可以把守卫区分catch块不同的错误的原因,并呼吁回调只有一次。但是,您需要另一个处理机制来处理您的错误。一个简单的可能性就是默默吞下新的错误,但这可能是一个不好的解决方案。

这就是异步编程的问题,当堆栈上下文丢失,直到最终执行回调时,不会有错误冒泡到中央处理程序。

干杯, 菲利克斯