Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
677 views
in Technique[技术] by (71.8m points)

ajax - Rejecting Javascript Promises And Error Handling

I'm trying to wrap my head around the correct way to indicate a failure within a .then().

If the promise doesn't fail, (I.e. the operation that returns the promise does it' job properly, such as an AJAX request that returns a status 200), but I decide that the result isn't valid, usually I'd do a popup, explaining the issue to the user, and do a "return false;" to exit the method early.

However, with promises, if from within the .then(), I want to do something similar, I've been lead to believe that what I should do is throw an error instead, and presumably let this get caught by the .catch() that I've chained on.

My concern is that I want to distinguish between an operation within a promise that succeeded, but which I don't like the result of, and a failed operation within a promise.

For example, if I perform an AJAX call and it fails with a 404, that's not really recoverable, so it seems appropriate to reject with a popup saying something like "something went wrong".

However, if the AJAX request is successful (returns a status 200), but the response indicates that something isn't right (Like the user didn't fill out a field with a correct value), then I'd like to handle that a certain way, which might involve not just a popup with a message (e.g. maybe DOM manipulations, red text etc, things that I might not want to do if it's a 404).

Below are 2 examples to better explain what I mean.

The first being the original implementation with callbacks and the second being with promises (Wrapping the ajax call with the Q promise library to make it a proper promise).

Callback version:

    $.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 version:

    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();

In the promise version, if the request returns a 404 it will end up in the .catch() immediately right?

If data.IsSuccessful==false, then it will also end up in the .catch()?

What if I want to treat both failures differently, how would I go about that?

I'm not calling resolve or reject anywhere, is that problematic?

I'd like to make sure I'm following best practices as much as possible.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

TL;DR: You can use rejections for control flow, but in general they are for exceptional cases only


In the promise version, if the request returns a 404 it will end up in the .catch() immediately right?

Yes.

If data.IsSuccessful==false, then it will also end up in the .catch()?

Yes.

I'm not calling resolve or reject anywhere, is that problematic?

Not at all. You're not using the Promise constructor (which you don't need, as you already have a promise for the ajax result).

What if I want to treat both failures differently, how would I go about that?

Throw different kinds of errors so that you can distinguish them. Give them names, add special properties, do subclassing (in ES6 especially), or just look at the message.

with promises, if from within the .then(), I want to do something similar, I've been lead to believe that what I should do is throw an error instead

Not necessarily. You can do exactly the same as you did without promises - put an if-else in the callback (or an if with an early return if you prefer).

In terms of control flow and their result values,

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

and

.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
})

are pretty much equivalent (except for exceptions in do something and with code other than this throwing MyErrors). The major difference is when you want to chain additional .then(…) invocations between the then and catch. If you don't, just choose whatever you like better.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...