【问题标题】:ininfinite loop in promise catch with callback error承诺中的无限循环捕获回调错误
【发布时间】:2017-05-09 21:36:43
【问题描述】:

我非常确信我误解了 Promise 的工作原理,但很多阅读都未能解决我的问题。

我有一个调用另一个模块的现有代码,该模块刚刚被更改为使用 Promise。使用旧版本看起来像这样:

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() 的无限循环。从捕获中删除回调,一切都很好。谁能解释一下?

【问题讨论】:

  • 我从来没有遇到过这种情况,但是写过类似的代码。与您的asyncFuncwithPromisecb 有关。你的函数是如何使用的,asyncFuncwithPromise 是如何定义的?
  • 需要看那个CB功能。它在做你期望的事情吗?它返回和/或做什么?
  • 谢谢,我会深入研究 CB 功能(这不是我的),我只是想检查一下我所做的基本操作是否被误导。
  • 您发布的伪代码没有问题。我们必须查看真实代码(包括传入的回调中发生的情况),以便了解无限循环的来源。这个问题可能无法回答。
  • 现在你正在使用 Promise,通过返回一个 Promise 使你的函数“thenable”。现在从函数中清除 cb - 它不需要。

标签: javascript node.js promise bluebird


【解决方案1】:

除非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 时,成功和失败轨迹最初对应于解析器中提供的 resolvereject 函数。因此,这之间没有区别(功能上):

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() 回调被推迟到执行帧的下一个后继帧。

【讨论】:

  • 关于 Promise 某些方面的不错的教程,但我不确定这如何回答 OP 的问题。
  • @jfriend00 呵呵,是的,我知道这可能对这个问题没有帮助。但从他所呈现的,没有办法知道发生了什么。它可以进入循环循环的唯一方法是如果他的cb() 正在调用asyncFuncWithPromise()。我试图澄清 Promise 机制,希望它可能会引发“啊哈”时刻。
  • 我想我可以看到您正在尝试提供帮助,但我们真的希望 OP 澄清他们的问题,以便所有人都清楚,而不是试图猜测可能有什么帮助。跨度>
  • 其实这两个例子是有区别的。前者同步执行,后者异步执行。
  • @MadaraUchiha - 我不认为这是一个明显的区别,因为你看到已解决的承诺的唯一方法是通过 .then() 处理程序返回的承诺,它总是被称为异步。所以,调用者无论如何只能看到一个异步解析。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 2022-12-19
  • 1970-01-01
相关资源
最近更新 更多