我可以用 bluebird Promises 提前打破链条吗?

Can I break a chain early with bluebird Promises?

我不一定想出错,但我有:

getFromDb().then (tradeData) ->
  if not tradeData
    # DO NOT CONTINUE THE CHAIN
  else
    getLatestPrice tradeData
.then (latestPrice) ->
  ...
.then ->
  ...
.then ->
  ...
.catch (err) ->
  next err

如果没有 tradeData,我有什么方法可以中止链?

getFromDb().then (tradeData) ->
  if tradeData
    getLatestPrice tradeData ->
      .then (latestPrice) ->
        ...
      .then ->
        ...
      .then ->
        ...
      .catch (err) ->
        next err
  else
    getSomethingElse ->
       send("no data")

在 3.0 中,您将可以这样做:

p = getFromDb().then (tradeData) ->
  if not tradeData
    send("no data");
    p.break()
  else
    getLatestPrice tradeData
.then (latestPrice) ->
  ...
.then ->
  ...
.then ->
  ...
.catch (err) ->
  next err

虽然是一个可接受的答案,但我想告诉所有的 googlers,"break()" 功能已更改为 "cancel()"

像这样使用:

p = getFromDb().then (tradeData) ->
  if not tradeData
    send("no data");
    p.cancel(); // Look Here!!!!!!!!!!!!!!!!
  else
    getLatestPrice tradeData
.then (latestPrice) ->
  ...
.then ->
  ...
.then ->
  ...
.catch (err) ->
  next err

在此之前,请确保在配置中添加以下行:

Promise.config({
    cancellation: true
});

我只是想知道为什么不利用这样一个事实,即您可以 throw 随心所欲,而不仅仅是 instanceof Error。这样做被认为是不好的做法?在我看来,这取决于你想要完成的事情。 Promise 链可能会因各种原因而中断,但总的来说,这两者会分为两组。需要 Classic error occurearly break in chain。从逻辑上讲,第二个不能被视为应该是 instance of Error.

的东西
const handleError = (err) => {
  ...
}

const skip = (reason, ..., ...) => {
  /**
   * construct whatever you like
   * just for example here return reason
   */
  return reason
}

Promise.resolve()
.then(() => {
  if (iShouldEndChainEarlier) {
    throw skip('I would like to end chain earlier')
  }

  return asyncOperation1()
})
.then(results => {
  ...
  return asyncOperation2(results)
})
.then(... => {
  ...
})
.catch(interrupt => {
  if (interrupt instanceof Error) {
    return handleError(interrupt)
  }

  /**
   * Handle breaking promise chain earlier
   * having interrupt reason in scope
   */
})

如果从逻辑上讲,链中的早期中断可以被视为错误(完全可以是这种情况),您可以创建自定义错误并在 catch 块中区分两者。所以只是说在处理承诺链中可能发生的任何中断时可以考虑另一种方法。

我们可以争论这是否可以被视为反对节点中的 first error pattern。如果出现错误,最佳做法是调用 callback(err) 之类的回调,其中 err 实际上应该是 instanceof Error,否则 callback(null, data)。但另一方面,考虑到 .catch(fn) 对我来说只是 then(undefined, onRejected) 的糖,它似乎足以根据你所处的情况处理 onRejected 参数。