【问题标题】:Can I break a chain early with bluebird Promises?我可以用 bluebird Promises 提前打破链条吗?
【发布时间】:2015-04-18 18:42:06
【问题描述】:

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

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

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

【问题讨论】:

标签: javascript promise bluebird


【解决方案1】:

我只是想知道为什么不利用您可以throw 随心所欲的事实,而不仅仅是instanceof Error。这样做被认为是不好的做法?在我看来,这取决于您要完成的工作。 Promise 链可能会因各种原因而中断,但通常这两者会分为两组。 Classic error occur 和 early 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 参数。

【讨论】:

    【解决方案2】:

    虽然是公认的答案,但我想告诉所有的谷歌人,“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
    });
    

    【讨论】:

      【解决方案3】:
      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
      

      【讨论】:

      • 如果我想实现额外的分支逻辑怎么办?例如,如果有tradeData,则执行某些步骤,如果没有,是否执行其他步骤?
      • @Shamoon 使用else
      • @Esailija:为什么?我希望您还没有将goto 构建到承诺链中?编辑:糟糕,我现在已经阅读了您的答案。当然,取消自己并不那么清楚:-)
      • @Bergi 顺便说一句,在 3.0 中,您可以使用对象属性作为错误谓词,这样您就可以拥有 throw {label: "no data"},然后是 .catch({label: "no data"}, function(e){}) - 但在这种特殊情况下,我仍然会更喜欢 break,因为它应该是这里发生的事情非常直观。
      • @Esailija : 在 bluebird API bluebirdjs.com/docs/api-reference.html987654321@ 中没有提到 break
      猜你喜欢
      • 2016-09-03
      • 1970-01-01
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 2017-08-17
      • 2017-03-04
      • 2017-08-06
      • 2016-09-24
      相关资源
      最近更新 更多