2

I have the following JS methods:

    var foo = function() {
        var dfd = $.Deferred();
        console.log('foo');
        dfd.resolve();
        return dfd.promise();
    };
    var ajaxCall1 = function () {
        var dfd = $.Deferred();
        $.ajax({
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            url: 'xxxxxxx',
            data: { },
            success: function(response) {
                dfd.resolve();

            }
        });
        return dfd.promise();
    };
    var ajaxCall2 = function () {
        var dfd = $.Deferred();
        $.ajax({
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            url: 'xxxxxxx',
            data: {},
            success: function (response) {
                dfd.resolve();

            }
        });
        return dfd.promise();
    };
    var ajaxCall3 = function () {
        var dfd = $.Deferred();
        $.ajax({
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            url: 'xxxxxxx',
            data: {},
            success: function (response) {
                dfd.resolve();

            }
        });
        return dfd.promise();
    };

and I am calling them via this code:

    foo().done(function () {
        return ajaxCall1();
    }).done(function () {
       return  ajaxCall2();
    }).done(function () {
        return ajaxCall3();
    });

The issue is that ajaxCall2 is called before the success of ajaxcall1 has occurred. Can you help me fixing this? I need to make ajax calls one by one when success of previous one has occurred.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
Rocky Singh
  • 15,128
  • 29
  • 99
  • 146
  • 1
    `$.ajax()` already returns a deferred object, so there is really no reason to use a separate one. Instead of `return dfd.promise()`, just `return $.ajax({...})`. – Matt Ball Apr 19 '12 at 03:37

5 Answers5

2

Use the $.when

var deferredObject = $.ajax({});
$.when(deferredObject)
 .then(function(){
     var deferredobject2 = $.ajax({});
     $.when(deferredobject2)
      .then(function(){ alert('after 2nd ajax call');});

  }); 
dhinesh
  • 4,676
  • 2
  • 26
  • 44
2

First of all, you can return the results of the $.ajax calls directly since they are promises already (no need for an intermediate Deferred):

var ajaxCall1 = function () {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        url: 'xxxxxxx',
        data: { }
    });
};
var ajaxCall2 = function () {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        url: 'xxxxxxx',
        data: {}
    });
};
var ajaxCall3 = function () {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        url: 'xxxxxxx',
        data: {}
    });
};

Second, what you wanna use is .pipe() to effectively chain the calls:

foo().pipe(function () {
    return ajaxCall1();
}).pipe(function () {
    return  ajaxCall2();
}).pipe(function () {
    return ajaxCall3();
}).done(function() {
    // call1, call2 and call3 done in sequence
}).fail(function() {
    // one of the ajax requests failed
});
Julian Aubourg
  • 11,346
  • 1
  • 29
  • 29
0

Simplify.

function foo() {
    var dfd = $.Deferred();
    console.log('foo');
    dfd.resolve();
    return dfd.promise();
}

function ajaxCall1() {
    return $.ajax({
        type: 'POST',
        dataType: 'json',
        url: 'xxxxxxx',
        data: { },
        success: function(response) {
            console.log('ajaxCall1 success');
        }
    });
    return dfd.promise();
}

// and so on for ajaxCall2 and ajaxCall3

Enhance.

foo().done(function () {
    ajaxCall1().done(function () {
        ajaxCall2().done(function () {
            ajaxCall3();
        });
    });
});

http://jsfiddle.net/mattball/LxjDS/


Further reading:

Community
  • 1
  • 1
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • Can't we write foo().done(ajaxCall1()).done(ajaxCall2()).done(ajaxCall3()); ? The enhanced method looks a bit cumbersome. – Rocky Singh Apr 19 '12 at 03:54
  • That passes the value _returned_ by `ajaxCallX()` to `.done()`, which means that you're not going to be guaranteed execution order of each ajax call. If that's okay - then yes. Real example that I just produced: http://i.stack.imgur.com/C9roz.png (this fiddle: http://jsfiddle.net/mattball/EYJfq) – Matt Ball Apr 19 '12 at 03:56
  • If execution is not maintained then what do the "done" denotes there? I was thinking to call multiple asynchronous calls but in order I specified – Rocky Singh Apr 19 '12 at 04:01
  • From the API docs: _"`deferred.done()`: Add handlers to be called when the Deferred object is resolved."_ It adds "done" callbacks which are called when the **original** deferred object is resolved. In this case, that's the deferred returned by `foo()`. – Matt Ball Apr 19 '12 at 04:04
  • Can't we add some resolve deferred function in success of ajax call so that the done of successive methods is called only after success of previous ajax calls – Rocky Singh Apr 19 '12 at 04:08
0

Same as the other answer except simplifying the callbacks with Frame.js

var responses = [];
for(var i=0; i<1000; i++){
    Frame(function(callback){
        $.ajax('myserver.api', { 
            data:i, 
            type:'post', 
            complete:function(response) { 
                responses.push(response);
                callback();
            }
        });
    });
}
Frame.start();

Normally, slamming the browser with AJAX requests like this would cause the browser to hang, and the response variables would be returned in the order they are received, rather than the original order they were sent in. Adding Frame to the mix here sorts all that out.

Or you could just use it to flatten out the callbacks:

Frame(function(next){
    foo().done(next);
});
Frame(function(next){
    ajaxCall1().done(next);
});
Frame(function(next){
    ajaxCall2().done(next);
});
Frame(function(next){
    ajaxCall3().done(next);
});
Frame(function(next){
    //do more stuff
    next();
});
Frame.start();
BishopZ
  • 6,269
  • 8
  • 45
  • 58
0

I've had similar problems working heavily with SharePoint web services - you often need to pull data from multiple sources before you're able to continue working.

To solve it I embedded this kind of functionality into my AJAX abstraction library. You can easily define a request which will trigger a set of handlers when complete. However each request can be defined with multiple http calls. Here's the component:

DPAJAX at DepressedPress.com

This very simple example creates one request with three calls and then passes that information, in the call order, to a single handler:

    // The handler function
function AddUp(Nums) { alert(Nums[1] + Nums[2] + Nums[3]) };

    // Create the pool
myPool = DP_AJAX.createPool();

    // Create the request
myRequest = DP_AJAX.createRequest(AddUp);

    // Add the calls to the request
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [5,10]);
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [4,6]);
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]);

    // Add the request to the pool
myPool.addRequest(myRequest);

Note that unlike many of the other solutions provided this method does not force single threading of the calls being made - each will still run as quickly as the environment allows but the handler will only be called when all are complete. The component also supports user-defined numbers of requests so you can force single-threading easily if you like. It also supports the setting of timeout values and retry attempts if your service is a little flakey.

I've found it insanely useful (and incredibly simple to understand) for this kind of work.

Jim Davis
  • 1,230
  • 6
  • 11