Using $.Deferred() with nested ajax calls in a loop

烈酒焚心 提交于 2019-11-27 11:55:33

Yeah, using Deferred is the way to do that:

function a() {
    var def = $.Deferred();

    $.ajax("http://url1").done(function(data){
        var requests = [];

        for (var i = 0; i < 2; i++) {
             requests.push(b());
        }

        $.when.apply($, requests).then(function() { def.resolve(); });
    });

    return def.promise();
}

// called by a()
function b() {
    var def = $.Deferred(),
        requests = [];

    for (var i = 0; i < 2; i++) {
        requests.push($.ajax("http://url2").done(function(data){
            // do something
            console.log('b called');
        });
    }

    $.when.apply($, requests).then(function() { def.resolve(); });

    return def.promise();
}

function main(){
    $.when(a()).done(function(){
        console.log('all completed');
    });
}

//EDIT: Replaced .pipe with .done.

You could use an Array which is located in a higher context to push Promise / Deferred objects into. Then you could then use jQuery.when alongside Function.prototype.apply to pass all entries as arguments.

(function() {
    var promises = [ ],
        when = Function.prototype.apply.bind( jQuery.when, null );

    function a() {
         promises.push($.ajax("http://url1").pipe(function(data){
             for (var i = 0; i < 2; i++) {
                 console.log('a called');
                 b();
             }
         }));

         return promises;
    }

    function b() {
        for (var i = 0; i < 2; i++) {
            promises.push($.ajax("http://url2", function(data) {
                // do something
                console.log('b called');
            }));
        }
    }

    function main() {
        promises = [ ];

        when( a() ).done(function(){
            console.log('all completed');
        });
    }
}());

The question might be old, but since there's no correct solution yet I'll put an answer here. It properly chains the promises by using .then (previsouly been .pipe) to achieve the requested result:

function a() {
  return $.ajax("http://url1").done(function(data){
    console.log('a called');
  }).then(function(){
    return $.when(b(), b()); // no loop for simplicity
  });
}
function b() {
  return $.ajax("http://url2").done(function(data){
    console.log('b called');
  });
}

function main(){
  a().done(function(){
    console.log('all completed');
  }, function() {
    console.log('an error occured!');
  });
}

Depending on which result data should be available where the nesting/structure might be changed, but the overall ordering is correct.

I believe this can be fixed with callbacks, but a fiddle would have really helped me check for you.

 // called by main()
 function a(callback) {
   //set this to the number of loops that is going to happen
   var number = 2;
   return $.ajax("http://url1", function(data){
     console.log('a called');
     for (var i = 0; i < number ; i++) {
       b();
       if(number===i){
           callback();
       }
     }
   }
 }

 function main(){
    a(function(){
       //Function or code you want to run on completion.. 
    });
 }

Forgive me if this doesn't work, but i think its the right direction.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!