最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Deferred calls for multiple ajax calls - Stack Overflow

programmeradmin7浏览0评论

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.

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.

Share Improve this question edited Apr 19, 2012 at 4:06 Matt Ball 360k102 gold badges653 silver badges720 bronze badges asked Apr 19, 2012 at 3:35 Rocky SinghRocky Singh 15.5k31 gold badges106 silver badges146 bronze badges 1
  • 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 Commented Apr 19, 2012 at 3:37
Add a ment  | 

5 Answers 5

Reset to default 2

Use the $.when

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

  }); 

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

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/mattball/LxjDS/


Further reading:

  • How to chain ajax calls using jquery
  • jQuery Deferred not calling the resolve/done callbacks in order
  • jQuery deferred - do I need pipes or chains to achieve this pattern?

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', 
            plete: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();

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 plete. However each request can be defined with multiple http calls. Here's the ponent:

DPAJAX at DepressedPress.

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./Add.htm", [5,10]);
myRequest.addCall("GET", "http://www.mysite./Add.htm", [4,6]);
myRequest.addCall("GET", "http://www.mysite./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 plete. The ponent 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.

发布评论

评论列表(0)

  1. 暂无评论