拒绝JavaScript Promises和错误处理

4
我试图理解在 .then() 中正确指示失败的方法。如果 promise 没有失败(例如返回状态200的 AJAX 请求),但我决定结果无效,通常我会弹出一个窗口向用户解释问题,并执行 "return false;" 以尽早退出方法。
然而,对于 promises,如果我想在 .then() 中执行类似的操作,我被告知应该抛出错误,然后让 .catch() 捕获它。
我的担忧是,我想区分 promise 内部成功但结果不佳的操作和 promise 内部失败的操作。
例如,如果我执行一个 AJAX 调用并返回404,则无法恢复,因此拒绝并弹出一个消息框,显示“出现了一些问题”。
然而,如果 AJAX 请求成功(返回状态200),但响应表明某些内容不正确(例如用户没有填写正确值的字段),那么我希望以某种方式处理它,这可能涉及到不仅仅是弹出一个带有消息的弹窗(例如 DOM 操作、红色文本等),这些操作如果是404则可能不需要执行。
以下是两个示例,更好地说明我的意思。
第一个是使用回调函数的原始实现,第二个是使用 promises 的实现(使用 Q promise 库将其包装为适当的 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");

});

Promise版本:

    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()吗?
如果我想分别处理这两种失败情况,该怎么办?
我没有在任何地方调用resolve或reject,这有问题吗?
我希望尽可能遵循最佳实践。

因为他可能想要显示一些只能通过数据库检索的值,因此需要将这个值返回给客户端。这会从 AJAX 返回状态码 200。 - PIDZB
@Abayob可以在非“200”状态码下返回头部数据。 - charlietfl
@charlietfl 怎么做?你能用 JavaScript 解释吗?你有例子吗? - PIDZB
@Abayob,你可以在服务器上设置头部信息并检查响应状态。如果它是自定义状态,则可以读取 $.ajax xhr 对象的头部。 - charlietfl
@meagar 你说得对,我知道会有人提出这个观点。我的例子不太好。 我想要表达的是,如果操作返回200,但我想根据结果中的某些内容抛出异常,我希望将这种自定义逻辑的异常处理方式与404等情况区分开来。 - Steviebob
显示剩余2条评论
1个回答

4

简而言之:可以使用拒绝来控制流程,但通常它们仅适用于特殊情况


在Promise版本中,如果请求返回404,它会立即进入.catch(),对吗?
是的。
如果data.IsSuccessful==false,它也会进入.catch()吗?
是的。
我没有在任何地方调用resolve或reject,这有问题吗?
完全没有问题。您没有使用Promise构造函数(因为您已经有了一个用于ajax结果的promise)。
如果我想分别处理两种故障,该怎么办?
抛出不同类型的错误以便您可以区分它们。给它们命名,添加特殊属性,进行子类化(尤其是在ES6中),或者只查看消息。
使用promises时,如果我想从.then()中做类似的事情,我被告知应该抛出错误
不一定。您可以像没有promises那样做-在回调中放置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中有例外情况,以及使用其他代码抛出MyError时)。主要区别在于当您想要在thencatch之间链接额外的.then(…)调用时。如果不需要,请随意选择。


谢谢你的回答。 请问你能为我澄清一下你最后一段话吗? 你是说,如果我确实想要在一个 .then() 后面链接更多的 .then(),并且我从这个 .then() 中抛出了一个异常,那么我需要注意它们不会被调用,因为程序会直接跳到 .catch() 吗? - Steviebob
@Steviebob:是的,完全正确。这可能或可能不是你想要的。如果你不想让它们被调用但仍然想使用if-else,你可以嵌套then回调函数。 - Bergi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接