31

我花了太多时间寻找类似的问题并尝试解决方案,所以我希望有人有解决方案。

基本上,我希望在函数 a() 完成时收到通知。问题是该函数包含一个 ajax 调用和一个调用 b() 的循环,该循环又包含一个 ajax 调用。

用小提琴更新:http : //jsfiddle.net/hsyj7/1/

像这样:

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

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

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

那么我想看到的是,可能在顶部同时调用 a() :

a called
b called
b called
a called
b called
b called
all completed

相反,我得到

a called
all completed
b called
b called

或者它的一些变体。

我知道上面的代码在循环和 b() 中都缺少延迟功能。在我尝试过的一些变体中,从不调用 main() 中的 done() 处理程序。

有人知道怎么做吗?

4

4 回答 4

30

是的,使用Deferred是这样做的方法:

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

//编辑:替换.pipe.done.

于 2012-12-19T11:43:38.480 回答
2

这个问题可能很老,但是由于还没有正确的解决方案,所以我会在这里给出答案。它通过使用.then(previsouly been .pipe) 正确链接承诺以实现请求的结果:

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

取决于嵌套/结构可能会更改的结果数据应该可用,但总体排序是正确的。

于 2014-02-13T08:43:26.950 回答
2

您可以使用位于更高上下文中的Array将Promise / Deferred对象推送到其中。然后,您可以使用jQuery.when并列Function.prototype.apply将所有条目作为参数传递。

(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');
        });
    }
}());
于 2012-12-19T11:49:55.610 回答
1

我相信这可以通过回调来解决,但是小提琴真的可以帮助我检查你。

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

如果这不起作用,请原谅我,但我认为这是正确的方向。

于 2012-12-19T11:40:20.207 回答