$.each 的下一次迭代收到 AJAX-content

Next iteration of $.each when received AJAX-content

这个问题已经asked before,但已经快四年前了,也许有更好的解决方案。

我有一个 $.each 循环,其中 有时 通过 ajax.

获取额外的数据

我正在用获取的数据构建一个对象,在循环之后有一个函数从该对象生成 HTML。 问题是循环在 ajax 数据到达之前完成。 如果我在 HTML-generating-function 中放置一个警报,内容就会正确加载。

我正在寻找一个仅在循环和所有 ajax 调用完成时调用 HTML-generator-function 的解决方案。也许这是一个解决方案,计算开始的 Ajax 请求并等待所有请求完成?

我相信 jQuery deferred 对我来说是正确的解决方案,但我确实只找到所有内容都在循环内的示例。有人可以帮忙吗?

我已将我的代码精简到最重要的部分:

//goes through each testplace -->main loop
$.each(jsobject, function(key, value)
{
 //build object together...
  for (var i = 0, numComputer = jenkinsComputer.contents.computer.length; i < numComputer; i++)
  {
    //If the testplace is in both objects then fire AJAX request
    if (jenkinsComputer.contents.computer[i].displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
    {
      //next $.each-iteration should only happen when received the JSON
      var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
      $.when($.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1")).done(function(jenkinsUser) 
      {
        //build object together...
      });
    }
  }

}); //End of main Loop ($.each)
generateHTML(builtObject);

如果有人能给我一些建议,那就太好了。

这是关于解决方案的未经测试的简短示例。我希望这能给你想法。

// I guess that jsobject is array ..
// if it is not object you can use something like:
// var keys = Object.getOwnPropertyNames(jsobject)
(function () {
    var dfd = $.Deferred();

    function is_not_finished() {
        return jsobject.length > 0 && jenkinsComputer.contents.computer.length > 0;
    }

    (function _handleObject() {
        var key = jsobject.shift();
        var displayName = jenkinsComputer.contents.computer.shift().displayName;

        if (displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
        {
            //next $.each-iteration should only happen when received the JSON
            var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
            $.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1").done(function(jenkinsUser)
            {
                //build object together...
                if(is_not_finished()) {
                    setTimeout(_handleObject,0);
                } else {
                    dfd.resolve();
                }
            });
        } else if (is_not_finished()) {
            setTimeout(_handleObject,0);
        } else {
            dfd.resolve();
        }
    }());

    return dfd.promise();
}()).done(function () {
    generateHTML(builtObject);
});

我会这样做:

var thingstodo = $(jsobject).length;
var notfired = true;
$.each(jsobject, function(key, value)
{
 //build object together...
  for (var i = 0, numComputer = jenkinsComputer.contents.computer.length; i < numComputer; i++)
  {
    //If the testplace is in both objects then fire AJAX request
    if (jenkinsComputer.contents.computer[i].displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
    {
      //next $.each-iteration should only happen when received the JSON
      var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
      $.when($.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1")).done(function(jenkinsUser) 
      {
        //build object together...
        thingstodo--;
        if(thingstodo === 0 && notfired){
            notfired = false;
            generateHTML(buildObject);
        }
      });
    }else{
        thingstodo--;
    }
  }

}); //End of main Loop ($.each)
if(thingstodo === 0 && notfired){
    generateHTML(buildObject);
}