如何链接方法以便仅在最后获得结果?

How to chain methods in order to get results only at the end?

我有一个简单的服务方法,它收集了几个 .get(),我在 "printing" 部分遇到了一些麻烦,因为那时我只有一部分结果。

我正在做的是:

var service = function() {
  var players = []; // will hold 100 objects

  var getMembers = function(id) {
    $.get(url, function(data) {
      for(i=0; i<data.length; i++) {
        var p = data[i];
        // get more info for this member
        getMemberDetails(p.member_id);
        // put the current data into the players
        players.push(p);
      }
    });

    calculateAndPrint();
  };

  var getMemberDetails = function(id) {
    $.get(url, function(data) {
      var result = $.grep(players, function(e){ return e.member_id == id; });
      if (result.length == 0) { /* not found */ } 
      else if (result.length == 1) {
        // push new data to player object
        result[0].details = data;
      }
    });
  };

  var calculateAndPrint = function() {
    for(i=0; i<players.length; i++) {
      var p = players[i];
      console.log(p);
    }
  };
})();

这不起作用,因为当我到达 calculateAndPrint 时,details 甚至还没有设计...

所以我尝试了 $.Deferred(),我遇到的唯一问题是,如果我延迟 getMemberDetails 方法,该调用已经包含一个延迟调用(.get())并且我我又回到了同样的问题...

在所有 100 次调用之后,仅 运行 calculateAndPrint 的最佳选择是什么?

看起来很简单,但我只是一片空白:/

如果你使用 promises,这应该很容易:

var service = function() {
  var getMembers = function(id) {
      return Promise.when($.get("some service url"))
          .then(function (data) {
              return Promise.all(data.map(getMemberDetails));
          });
  };

  var getMemberDetails = function(player) {
      return Promise.when($.get("some service Url?id=" + player.member_id));
  };

  var calculateAndPrint = function(players) {
      players.forEach(function (player) {
          console.log(player);
      });
  };

  return {
      getMembers: getMembers,
      calculateAndPrint: calculateAndPrint
  };
})();

service.getMembers().then(function (players) {
    service.calculateAndPrint(players);
});

您可以为每个 ajax 调用创建一个延迟对象 $.deferred,然后等待 ($.when) 所有这些延迟作业在您 [=66= 之前完成] calculateAndPrint() 方法。


工作原理:

  • 为每个 ajax 调用创建一个延迟对象 $.deferred & return promise 对象 .promise().
  • 根据 ajax 调用是否成功,使用响应数据 .resolve(responseData) 解决或使用错误数据 .reject(errorData).
  • 拒绝
  • 监视所有 ajax 调用 return 从第 1 步开始的承诺对象,并在完成时调用 calculateAndPrint() 方法。
  • 对于任意 ajax 调用,上述大部分逻辑保持不变,除了那些在 for 循环中调用并且每个延迟调用都被推入一个 deferredCalls 数组。

注意:我建议您在拨打 ajax 电话时显示一些 loader/spinner 图片,因为您不会立即得到响应并让用户了解后台操作总是好的用户体验标志。

JS代码:

/* utils */
var $ul = $('ul');

function msg(text) {
  $ul.append('<li>' + text + '</li>'); 
}

/* functions */
function asyncThing1() {
  var dfd = $.Deferred();
  setTimeout(function() {
    msg('asyncThing1 seems to be done...');
    dfd.resolve('banana');
 }, 1000);
 return dfd.promise();
}

function asyncThing2() {
  var dfd = $.Deferred();
    setTimeout(function() {
    msg('asyncThing2 seems to be done...');
    dfd.resolve('apple');
  }, 500);
  return dfd.promise();
}

function asyncThing3() {
  var dfd = $.Deferred();
  setTimeout(function() {
    msg('asyncThing3 seems to be done...');
    dfd.resolve('orange');
  }, 1500);
  return dfd.promise();
}

/* do it */
$.when(asyncThing1(), asyncThing2(), asyncThing3()).done(function(res1, res2, res3) {
  msg('all done!');
  msg(res1 + ', ' + res2 + ', ' + res3);
});

Live Demo @ JSFiddle


任意延迟调用 Original SO Post :

//Push all arbitrary ajax calls to deferred array
var deferreds = [];
function getSomeDeferredStuff() {
   var i = 1;
   for (i = 1; i <= 10; i++) {
      var count = i;
      deferreds.push(
        $.post('/echo/html/', {
          html: "<p>Task #" + count + " complete.",
          delay: count
        }).success(function(data) {
           $("div").append(data);
      }));
   }
}


// define a extension method for $.when for creating/managing deferred
// objects for every ajax call
if (jQuery.when.all===undefined) {
   jQuery.when.all = function(deferreds) {
      var deferred = new jQuery.Deferred();
      $.when.apply(jQuery, deferreds).then(
          function() {
             var deferredObjs= function (arguments) { return deferreds.length > 1 ? $.makeArray(arguments) : [arguments]; }
             deferred.resolve(deferredObjs);
          },
          function() {
             deferred.fail(deferredObjs);
          });

      return deferred;
   }
}

//passing the deferred calls array to $.when
$.when.all(deferreds).then(function(objects) {
    //process when all deferred objects compelted
    console.log("Resolved/rejected objects:", objects);
});

Working example for arbitrary ajax calls @JSFiddle