13

I have an $.ajax promise and want to check whether my (syntactically valid) response contains an error, triggering the rejected status in that case.

I have worked with my own promise library which deals such tasks easily. I do not really like jQuery's Promise (cache) implementation with its Deferred object and may have overlooked something, because I seldom use it. I think the way to go is just using .then(), which seems to be rather complicated:

return $.ajax(...).then(function success(response) {
    var problem = hasError(response);
    if (problem) {
        var error = new $.Deferred;
        error.reject(problem);
        return error;
    } else
        return response;
});

This should return a promise which is rejected in case of network errors or problems with the response. But is returning a rejected deferred really the [only|best|shortest] way to go?

I also would appriciate help on how to deal with such "error-throwing response handlers" in the ajax options themselfes, I could not find good documentation about them.


Disclaimer: No, I cant change the server responses. The problem-detecting method is synchronous. I don't want to use other libraries, I'm particularly interested in the way jQuery solves this.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • OK, with `.then()` I meant the thing that `.pipe()` does in jQuery :-( – Bergi Jun 01 '12 at 02:03
  • agreed! I can only imagine the world of pain we would be in with different promise-consuming libraries if JQuery had decided to stick with a non-standard spec! Grats to them on making the breaking change, in order to spare us all that pain had it been allowed to go on. – Plynx Oct 16 '12 at 23:28

1 Answers1

33

Now updated for jQuery 1.8+

The easiest way to tackle this is to run the response of $.ajax through .then to filter based on success or failure of the data.

$.ajax()
    .then(function (response) {
        return $.Deferred(function (deferred) {
            var problem = hasError(response);

            if (problem) {
                return deferred.reject(problem)
            }

            deferred.resolve(response);
        }).promise();
    });

You could then return this new promise to whatever calling code would consume this:

var request = function () {
    return $.ajax()
        .then(function (response) {
            return $.Deferred(function (deferred) {
                var problem = hasError(response);

                if (problem) {
                    return deferred.reject(problem)
                }

                deferred.resolve(response);
            }).promise();
        });
};

request()
    .done(function (response) {
        // handle success
    })
    .fail(function (problem) {
        // handle failure
    });
Eli
  • 17,397
  • 4
  • 36
  • 49
  • What's the difference between pipe and then? – Bergi Jun 01 '12 at 01:40
  • 1
    `pipe` allows you to filter a deferred's values before they are sent to any registered promise handlers. `then` is really just used to register handlers when a promise resolves or rejects. – Eli Jun 01 '12 at 01:43
  • 1
    No, [by specification](http://webcache.googleusercontent.com/search?q=cache%3awiki.commonjs.org/wiki/Promises/A) .then() would do exactly that. Or did jQuery threw this up and swapped method names? – Bergi Jun 01 '12 at 01:50
  • 5
    jQuery Deferreds are not Promises/A compliant. They are a derivation of Promises/A and "Promises/J" http://jaubourg.net/38261410. – Eli Jun 01 '12 at 01:52
  • Uh, that's good to know. I will read through that article tomorrow. – Bergi Jun 01 '12 at 02:01
  • Sorry, there was an error in the code. It should now be fixed, and updated to work with jQuery 1.8+. – Eli Mar 29 '13 at 00:44
  • Note that jQuery is attempting to make Deferreds more like Promises/A. – Eli May 02 '13 at 15:21
  • @BenjaminGruenbaum, after editing, what are `deferred` and `problem`? – Roamer-1888 Aug 14 '14 at 18:34
  • Good catch, I was careless. Fixed. – Benjamin Gruenbaum Aug 14 '14 at 20:43
  • @Eli What are "Promises/J"? I can't find any references. jaubourg.net looks empty of content. – Vladislav Rastrusny Feb 26 '15 at 11:13
  • Responding to the first comment: It seems that .then() was changed to behave like pipe. The [jQuery docs say](https://api.jquery.com/deferred.then/): "As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method." – Matthijs Kooijman Nov 21 '18 at 15:07