如何使用回调包装承诺?

时间:2017-01-13 21:55:18

标签: javascript node.js callback es6-promise

在我工作的公司中,目前一切都是通过回调来完成的。我们开始用大代码所依赖的承诺编写小组件。我们开始遇到麻烦了。

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。问题是如果在回调中抛出错误,回调将触发两次。

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

之间存在细微差别
.then(onFulfilled, onRejected)

.then(onFullfilled)
.catch(onRejected)

第一个将无法捕获onFullFilled回调中抛出的错误,而第二个回调。因此,您可能不应该在当时阶段使用onRejected回调,只需像在第二个代码段中那样链接.catch()

答案 1 :(得分:0)

您可以将then部分中的代码分开,以便在调用 cb 之前的错误与 cb 中发生的错误区别对待。您可以返回字符串值,而不是在那里调用 cb ,以便可以在链式then方法中使用它。在那里你可以使用成功和失败之间的切换。那样 cb 只会在那里被调用。

现在,如果通过调用 cb 发生错误,您可以使用最终.catch来捕获它,但之后您不会再调用 cb ,但也许只输出一些东西,或者级联错误,或者做那些你想做的事情。

这是一个包含三个用例的演示:

  1. 没有错误
  2. (第一个)then
  3. 中的错误
  4. cb
  5. 中的错误

    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块中的不同错误原因,并且只调用一次回调。但是,您需要另一种处理机制来处理错误。一个简单的可能性是默默地吞下新的错误,但这可能是一个糟糕的解决方案。

这就是异步编程的问题,因为在最终执行回调之前堆栈上下文丢失,所以不可能将错误冒泡到中央处理程序。

干杯, 菲利克斯