【问题标题】:Error handling with promises chain使用承诺链进行错误处理
【发布时间】:2015-09-16 08:42:37
【问题描述】:

我有一连串的承诺

promisedStep1()
    .then(promisedStep2)
    .then(promisedStep3)
    .then(promisedStep4)
    .then(function (value4) {
        // Do something with value4
    })
    .catch(function (error) {
        // Handle any error from all above steps
    });

而且我需要知道我在哪一步出错了。

如果我在每个承诺的步骤中添加 catch

promisedStep1()
    .catch(function(){
        throw {code: 1}
    })
    .then(promisedStep2)
    .catch(function(){
        throw {code: 2}
    })
    .catch(function (error) {
        console.log('error in ', error.code);
    });

code 将始终为 2,因为它从第一次捕获到第二次。

处理此类错误的技术是什么?

编辑

找到了一条路:

function promisedStep1Wrapper(){
    return promisedStep1()
        .catch(function(){
            throw {code: 1};
        });
}

function promisedStep2Wrapper(){
    return promisedStep2()
        .catch(function(){
            throw {code: 2};
        });
}

promisedStep1Wrapper()
    .then(promisedStep2Wrapper)
    .catch(function(err){
        console.log(err.code);
    });

这样可以吗,还是有更好的解决方案?

【问题讨论】:

标签: javascript error-handling promise


【解决方案1】:

这样好吗?

是的,完全是。

或者有没有更好的解决方案?

“更好”我不知道,但肯定还有其他的。一种方法是只处理您期望的那些错误 - 上一步中的错误,然后重新抛出其他所有错误。一些像 Bluebird 这样的库确实为这种绝对优越的方法提供了专用的帮助函数。它基本上看起来像这样:

promisedStep1() // throws Step1Error
.catch(function(err) {
    if (!(err instanceof Step1Error)) throw err;
    throw {code: 1};
})
.then(promisedStep2) // throws Step2Error
.catch(function(err) {
    if (!(err instanceof Step2Error)) throw err;
    throw {code: 2};
})
.catch(function(error) {
    if (!("code" in error)) throw error; // duck typing
    console.log('error in ', error.code);
})
.catch(function(error) {
    console.error("completely unexpected:", error);
});

另一种方法是嵌套并使用第二个 then 回调进行专门的错误处理 - 请参阅 When is .then(success, fail) considered an antipattern for promises? 以了解与 .then().catch() 的区别。使用它,您的代码将如下所示

promisedStep1()
.then(function(res) {
    return promisedStep2(res)
    .then(function(res) {
        // do something
        return res;
    }, function(err) { // error in promisedStep2
        throw {code: 2};
    });
}, function(err) { // error in promisedStep1
    throw {code: 1};
})
.catch(function(error) {
    if ("code" in error)
        console.log('error in ', error.code);
    else
        console.error("completely unexpected:", error); // from "do something"
});

这种方法效果很好,允许对附加处理程序的位置进行细粒度控制,将成功和错误路径清晰地分开,但在语法上有点混乱。

【讨论】:

  • 在第一种方法中,例如promisedStep1 是一个单独的模块,它会抛出实例Step1Error 的错误。所以它的自定义错误在这个模块内部定义,构造函数Step1Error继承自Error。为了在这个模块之外检查err instanceof Step1Error,我们需要构造函数Step1Error 的引用,对吧?否则会抛出错误 - Step1Error is not defined.
  • 是的,您当然需要对构造函数的引用。但是,如果库/模块定义了它们自己的 Error 子类,它们通常会暴露它(例如 step1module.Error)。否则,自定义错误主要与自定义属性一起使用,您可以通过鸭子类型来检测这些错误(例如您的示例中的 .code 事物)。
猜你喜欢
  • 1970-01-01
  • 2015-07-03
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 2018-06-01
  • 2018-09-18
相关资源
最近更新 更多