【问题标题】:Break javascript promise chain in a clean way以干净的方式打破 javascript 承诺链
【发布时间】:2017-04-26 09:57:52
【问题描述】:

我正在尝试链接承诺,这样如果一个承诺被拒绝,链就会中断。我遵循previous SO question 的线索并尝试将其应用于原生承诺,但我认为我误解了事情的运作方式。

这是我重写代码的方式:

Promise.resolve()
    .then(function() {
        return step(1)
            .then(null, function() {
                stepError(1);
            });
    })
    .then(function() {
        return step(2)
            .then(null, function() {
                stepError(2);
            });
    })
    .then(function() {
        return step(3)
            .then(null, function() {
                stepError(3);
            });
    });

function step(n) {
    console.log('Step '+n);
    return (n === 2) ? Promise.reject(n) : Promise.resolve(n);
}

function stepError(n) {
    console.log('Error '+n);
    return Promise.reject(n);
}

以上代码的输出为:

Step 1
Step 2
Error 2
Step 3
[UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): 2]

在我的理解中,第 2 步应该打破链条,第 3 步不应该执行。当 step(2) 返回一个被拒绝的 promise 时, stepError(2) 会按预期执行。但是由于它返回 Promise.reject(2),因此不应执行下一个 then 中的函数,并且由于最后没有 catch,因此步骤 2 的拒绝承诺似乎 - 正如预期的那样 - 被转发直到它退出链,因为它没有找到任何处理程序。

我在这里错过了什么?

这是一个可以玩的 JSFiddle:https://jsfiddle.net/6p4t9xyk/

【问题讨论】:

    标签: javascript promise


    【解决方案1】:

    据我了解,第 2 步应该会打破链条...

    ,但你不小心将拒绝转化为解决方案。

    关于 Promise 的关键在于,每次调用 then 都会创建一个 new Promise,该 Promise 会根据 then 回调所做的事情来解决/拒绝,并且回调处理拒绝会将拒绝转换为解决方案,除非它故意不这样做。

    所以这里:

    return step(2)
        .then(null, function() {  // This handler converts the
            stepError(2);         // rejection into a resolution
        });                       // with the value `undefined`
    

    这样您就可以拥有补偿错误的错误处理程序。

    由于stepError 返回拒绝,您只需添加return 即可继续拒绝:

    return step(2)
        .then(null, function() {
            return stepError(2);  // Added `return`
        });
    

    ...或者,完全删除该处理程序:

    return step(2);
    

    ...或者你可以在回调中throw,它会自动变成拒绝。

    未处理的拒绝警告是由于没有消耗来自stepError 的拒绝。


    这是一个返回stepError结果的例子:

    Promise.resolve()
        .then(function() {
            return step(1)
                .then(null, function() {
                    return stepError(1); // Added `return`
                });
        })
        .then(function() {
            return step(2)
                .then(null, function() {
                    return stepError(2); // Added `return`
                });
        })
        .then(function() {
            return step(3)
                .then(null, function() {
                    return stepError(3); // Added `return`
                });
        });
    
    function step(n) {
        console.log('Step '+n);
        return (n === 2) ? Promise.reject(n) : Promise.resolve(n);
    }
    
    function stepError(n) {
        console.log('Error '+n);
        return Promise.reject(n);
    }

    【讨论】:

      【解决方案2】:

      正如@T.J.Crowder 所说,您忘记了return 错误处理程序的结果(或来自它的throw)。要修复它,我建议您这样做

      function withStepError(n, promise) {
          return promise.catch(function(err) {
              console.log('Error '+err+' from '+n);
              throw new Error("failed at "+n);
          });
      }
      Promise.resolve()
      .then(function() {
          return withStepError(1, step(1));
      })
      .then(function() {
          return withStepError(2, step(2));
      })
      .then(function() {
          return withStepError(3, step(3));
      });
      

      function getStepError(n) {
          return function(err) {
              console.log('Error '+err+' from '+n);
              throw new Error("failed at "+n);
          };
      }
      
      Promise.resolve()
      .then(function() {
          return step(1).catch(getStepError(1));
      })
      .then(function() {
          return step(2).catch(getStepError(2));
      })
      .then(function() {
          return step(3).catch(getStepError(3));
      });
      

      【讨论】:

        猜你喜欢
        • 2020-02-23
        • 2017-11-23
        • 2014-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-13
        相关资源
        最近更新 更多