【问题标题】:Rejecting Javascript Promises And Error Handling拒绝 Javascript Promise 和错误处理
【发布时间】:2016-09-18 19:08:14
【问题描述】:

我正试图用正确的方法来表示 .then() 中的故障。

如果promise没有失败,(即返回promise的操作可以正常工作,例如返回状态200的AJAX请求),但我认为结果无效,通常我'd 会弹出一个窗口,向用户解释问题,然后执行“return false”;提前退出方法。

但是,通过承诺,如果在 .then() 中,我想做类似的事情,我被引导相信我应该做的是抛出一个错误,并且大概让它被.catch() 我已经链接了。

我担心的是,我想区分 Promise 中成功但我不喜欢其结果的操作,以及 Promise 中失败的操作。

例如,如果我执行 AJAX 调用并失败并返回 404,这实际上是不可恢复的,因此似乎可以通过弹出窗口说“出现问题”来拒绝。

但是,如果 AJAX 请求成功(返回状态 200),但响应表明有问题(比如用户没有填写正确值的字段),那么我想以某种方式处理该问题,这可能不仅仅涉及带有消息的弹出窗口(例如,可能是 DOM 操作、红色文本等,如果是 404,我可能不想做的事情)。

下面是 2 个例子,可以更好地解释我的意思。

第一个是带有回调的原始实现,第二个是带有 Promise 的(使用 Q Promise 库包装 ajax 调用以使其成为正确的 Promise)。

回调版本:

    $.ajax({
    url: "/cars/1",
    type: "GET",
    contentType: "application/json; charset=utf-8",
    dataType: "json"
})
.done(function (data) {
    if (!data.IsSuccessful) {
        //The request was successful (status 200), but the server is returning IsSuccessful=false
        alert(data.Message);//message says something like "we have that car in our catalogue but we don't have it in stock"
        return false;//early exit from .done()
    }

    //if it gets here, everything is good and I can do something with the result
})
.fail(function (data) {
    //The request actually failed due to a generic status 500 error which has something I don't necessarily want to expose in a popup to the user
    alert("Something went wrong");

});

承诺版本:

    var myPromise = Q(
    $.ajax({
        url: "/cars/1",
        type: "GET",
        contentType: "application/json; charset=utf-8",
        dataType: "json"
    })
);

myPromise.then(function (data) {
    if (!data.IsSuccessful) {
        throw new Error(data.Message);
    }

    //all good, lets do something with the result
})
.catch(function (error) {

    //what is error?
    //How do I know if it's one that I want to show to the user or not?

}).done();

在 promise 版本中,如果请求返回 404,它将立即以 .catch() 结束,对吗?

如果data.IsSuccessful==false,那么它也会以.catch()结束?

如果我想以不同的方式处理这两种失败,该怎么办?

我没有在任何地方调用解决或拒绝,这有问题吗?

我想确保我尽可能地遵循最佳做法。

【问题讨论】:

  • 为什么不只依靠状态码来完成他们的工作呢?你为什么要提供一个带有isSuccessful: false 属性的 200 响应? 2xx 响应码都表示请求成功
  • 因为他可能想要显示一些只能由数据库检索的值,因此需要将该值返回给客户端。这给出了来自 AJAX 的状态 200。
  • @Abayob 可以在非 200 的标头中返回数据
  • @charlietfl 怎么样?你能用 JavaScript 解释它吗?你有例子吗?
  • @Abayob 您在服务器上设置标头消息并检查响应状态,如果是自定义状态,请读取作为 $.ajax xhr 对象一部分的标头

标签: javascript ajax error-handling promise es6-promise


【解决方案1】:

TL;DR:可以使用rejections for control flow,但一般来说它们是exceptional cases only


在 promise 版本中,如果请求返回 404,它将立即在 .catch() 中结束,对吗?

是的。

如果 data.IsSuccessful==false,那么它也会在 .catch() 中结束?

是的。

我没有在任何地方调用解决或拒绝,这有问题吗?

一点也不。您没有使用 Promise 构造函数(您不需要它,因为您已经对 ajax 结果做出了承诺)。

如果我想以不同的方式处理这两种失败,该怎么办?

抛出不同类型的错误,以便您能够区分它们。给它们命名,添加特殊属性,进行子类化(尤其是在 ES6 中),或者只是查看消息。

有了承诺,如果在 .then() 中,我想做类似的事情,我一直相信我应该做的是抛出一个错误

不一定。你可以做与没有承诺时完全相同的事情 - 在回调中放置一个 if-else(或者如果你愿意,可以使用一个带有提前返回的 if)。

就控制流及其结果值而言,

.then(function(res) {
    if (!res.isOK) {
        // do something
        return false;
    }
    // do something else
}).catch(function(err) {
    // handle something
})

.then(function(res) {
     if (!res.isOK)
         throw new MyError(res);
     // do something else
}).catch(function(err) {
     if (err instanceof MyError) {
         // do something
         return false;
     }
     // handle something
})

几乎是等价的(do something 中的异常和除了这个抛出 MyErrors 之外的代码)。主要区别是当您想要在thencatch 之间链接额外的.then(…) 调用时。如果你不这样做,就选择你更喜欢的。

【讨论】:

  • 感谢您的回答。你能帮我澄清一下你的最后一段吗?你是说如果我确实想从我抛出异常的 .then() 中链接额外的 .then(),我需要注意它们不会被调用,因为它会直接跳转到 .then() 。捕捉()?
  • @Steviebob:是的,完全正确。这可能是也可能不是你想要的。如果你不想让它们被调用并且仍然想使用if-else,你可以嵌套then回调。
猜你喜欢
  • 2016-02-19
  • 1970-01-01
  • 2015-04-26
  • 2018-08-26
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 2016-11-10
  • 2017-06-02
相关资源
最近更新 更多