Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deferred jQuery AJAX wrapper

I'm creating a wrapper for the jQuery AJAX method because my AJAX requests depend on asynchronous work before actually proceeding.

What I'm currently doing is this: http://pastie.org/private/bfdvep4kcdclzupsyddmiq

var ajax = function (options) {
    var deferred = $.Deferred();

    doAsyncWork()
    .done(function (attributes) {
        $.ajax(options)
        .done(function () {
            deferred.resolve.apply(this, arguments);
        })
        .fail(function () {
            deferred.reject.apply(this, arguments);
        });
    })
    .fail(function () {
        deferred.reject();
    });

    return deferred.promise();
};

ajax().readyState // undefined

It has an outer deferred that returns a promise. I fire doAsyncWork() and wait for it to complete before actually doing the AJAX request. Now, while this works, the problem is that when other scripts use the wrapper because they can't access the properties of the jQuery XHR object.

Is there a way to solve this elegantly?

like image 827
Morten Avatar asked Apr 29 '26 23:04

Morten


1 Answers

The question is: why should they? Do you try to replace $.ajax() transparently with your wrapper? This will get complicated quickly, as you will have to consider all properties and methods of jqXHR.

In theory, something like this is possible, but I would not call it elegant and not recommend it:

var ajax = function (options) {
    var deferred = $.Deferred();
    var promise = deferred.promise();

    doAsyncWork()
    .done(function (attributes) {
        $.ajax(options)
        .done(function () {
            promise.readyState = 4
            deferred.resolve.apply(this, arguments);
        })
        .fail(function () {
            promise.readyState = 4
            deferred.reject.apply(this, arguments);
        });
    })
    .fail(function () {
        deferred.reject();
    });

    promise.readyState = 0;
    return promise;
};

The other readystate settings should go to the appropiate callbacks (there is no onreadystatechange in JQuery).

So, what to do instead?

If other scripts want to use your wrapper, they will have to use the Deferred API. If for some reason they really need to get access to the jqXHR object, you can supply it like this:

var ajax = function (options, xhrReadyCallback) {
    var deferred = $.Deferred();

    doAsyncWork()
    .done(function (attributes) {
        var xhr = $.ajax(options)
        .done(function () {
            deferred.resolve.apply(this, arguments);
        })
        .fail(function () {
            deferred.reject.apply(this, arguments);
        });
        xhrReadyCallback(xhr);
    })
    .fail(function () {
        deferred.reject();
    });

    return deferred.promise();
};

Usage:

ajax(options, function(xhr) {
    // now available:
    xhr.readyState;
});
like image 96
Fabian Schmengler Avatar answered May 01 '26 23:05

Fabian Schmengler