11

介绍

这个问题旨在最终解决我在开发 Bluebird 时遇到的问题。但是,我也在利用这个机会澄清一些事情,所以会有一些附带问题。对于您在阅读即将到来的故事时可能遇到的任何困惑或无聊感,我也提前道歉。


问题

据我了解,Bluebird 会根据以下策略智能地捕捉被忽略的拒绝:

第二种方法是 bluebird 默认采用的方法,如果拒绝在第二轮开始时未处理,则调用已注册的处理程序。-- Bluebird 自述文件 # 错误处理

现在这里存在第一个侧面问题:“第二轮的开始”是什么意思?

稍后在同一部分中,记录了以下内容:

当然,这并不完美,如果您的代码出于某种原因需要在某个 Promise 挂起一段时间后突然介入并将错误处理程序附加到某个 Promise 上,那么您将看到烦人的消息。在这种情况下,您可以使用 .done() 方法来表示应该抛出任何挂起的异常。-- Bluebird 自述文件 # 错误处理

现在,我相信我遇到了上述情况,我的用例如下:

  • 我调用一个函数,它将为我提供我附加的承诺.catch()

    lib.loadUrls()
    .catch(function(e){console.log(e);});
    
  • 在内部,该函数从 URL1 加载内容并根据内容依次从 URL2 加载内容:

    lib.loadUrls =
      return this.loadUrl1()
      .then(this.loadUrl2.bind(this))
    
  • 如果此链中的第二个承诺被拒绝,则错误首先由 catch 处理,然后由 BluebirdsPossibly unhandled error处理程序处理。

最后一种行为是不需要的,我无法弄清楚它为什么会这样做。所以问题二可能是:为什么尽管附加并执行了错误处理程序,Bluebird 仍然考虑错误被“未处理”的可能性?

我在想,当拒绝传播到.catch(). 在这种情况下,我应该通过“使用”来解决它(根据引用的文档).done()

现在,我已经尝试了几件事,但我不太清楚在这种情况下如何“使用 .done”。(返回 undefined 并没有帮助.done(),阻止我.finally-ing。)

所以这引入了我的第三个和第四个问题:在这种情况下我如何使用.done(),以及我如何明确地结束一个承诺链,但仍然附加一个.finally()

编辑 1:我创建了一些 JSFiddles 来重现该错误:

编辑 2:开发人员修复了错误。

4

2 回答 2

4

这确实只是蓝鸟中的一个回归错误,现在已修复。

关于需要使用.done()的内容几乎是理论上的,您不会在实践中运行需要以会导致报告误报的方式附加错误处理程序的情况。

于 2014-02-18T18:10:27.633 回答
1

这很可能是 Bluebird 错误,因为不应报告已处理loadUrls的错误(假设您正确处理了正文中的承诺)。因此,您可能应该将其报告给 Bluebird 问题跟踪器。

关于done,最好使用纯访问函数来代替thencatch仅在处理已解析值时使用。

最好将其done视为首选功能和使用then,并且catch仅当您确实需要转换为其他承诺时,使用这种方法您也不需要依赖错误的错误监控(最好完全关闭它)。

在您的情况下done,应用作:

lib.loadUrls().done(); // eventual error will be thrown

如果由于某种原因您想专门处理错误(例如,在运行的服务器中您不希望它抛出),请执行以下操作:

lib.loadUrls().done(null, function (error) {
  // handle error
});

编辑:

刚刚注意到,您仍然想处理lib.loadUrls().catch(..)with返回的承诺finally。在这种情况下done不是解决方案。done应该只用作最终调用,但您可以将其与finally如下组合:

lib.loadUrls().finally(function () {
  // cleanup
}).done();
于 2014-02-18T07:58:11.833 回答