【问题标题】:Next iteration of $.each when received AJAX-content收到 AJAX 内容时 $.each 的下一次迭代
【发布时间】:2016-04-13 12:46:49
【问题描述】:

问题一直是asked before,不过差不多是四年前的事了,也许有更好的解决方案。

我有一个 $.each 循环,有时会通过 ajax 获取额外的数据。

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

我正在寻找一种仅在循环和所有 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);

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

【问题讨论】:

  • 小提示:循环中的 AJAX 绝不是一个好主意。看起来可能比较简单,但还是让服务端做循环比较好。
  • 整个脚本在我们的本地网络上运行,大部分时间只有 5-10 个短的 ajax 调用,所以这里没有网络问题。如果有 javascript 解决方案,那就太好了。

标签: javascript jquery ajax asynchronous jquery-deferred


【解决方案1】:

我会这样做:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 您在执行 ajax 请求时阻止了整个执行,而不是让它异步运行。
    • 嗯。实际上 $.each 是同步的。如果接收数据的顺序不重要,您的解决方案就可以,因为您同时发送请求。这里的关键是“接收时的下一次迭代”。我们还可以开发像 $.eachAsinc 这样依赖于 promise 的东西。同样在您的情况下 $.when 是不必要的,因为 $.getJSON 返回承诺。
    猜你喜欢
    • 2015-05-12
    • 2018-07-15
    • 1970-01-01
    • 2021-02-26
    • 1970-01-01
    • 2017-03-16
    • 2016-07-13
    • 2012-10-13
    • 2014-06-30
    相关资源
    最近更新 更多