$ .each $ .getJSON竞争条件?

时间:2014-09-04 10:12:42

标签: javascript jquery ajax

jquery.each()内使用jquery.getJSON功能时遇到问题。 在这种情况下,我在代码中处理了两种类型的元素。 “来源”和“流” 我想使用getJSON来获取源代码,迭代它们并从中生成一个手风琴标题。然后,对于每个“源”,我再次使用getJSON与该源的id来获取它的相应“流”。然后我将这些流附加到它的源手风琴主体,以获得所有流的列表,按其来源排序。

但是当我得到JSON时,我的程序中的下一个语句已经执行了。因为我基本上是动态构建一个大的HTML String并使用jQuery将它添加到一个元素,所以String不能获得它需要的所有数据。

代码如下:

var html1 = "<div class='panel-group' id='manageAccordion'>";
$.getJSON(url, function(data){
    $.each(data, function(i, json){
        html1 += getAccordionPart(...); //creates the accordion for the given source
    });

}).done(function(){
    html1 += "</div>";
    $('#elementList').html(html);
});

function getAccordionPart(id, parent, count, json){ 
    //new string html2 is created and a bunch of stuff added
    //...
    html2 += "...."; 
    html2 += getAccordionBody(json);
    html2 += "</div></div></div></div>";
    return html2
}

function getAccordionBody(json){
//new string "html3" gets created
//...

 var url = standardUrl + "sources/" + encodeURIComponent(json.elementId) + "/streams";
 $.getJSON(url, function(data) {
    $.each(data, function(i, json) {
        html3 += "<li class='list-group-item'>";
        html3 += json.name;
        html3 += "</li>";
    });

}).done(function(){
    html3 += "</ul>";
    return html3;
});

}

我最后得到的是一个手风琴标题,它的身体“未定义”, 因为在将html字符串添加到DOM之前,getAccordionBody()函数似乎没有返回。

我已尝试在$.getJSON两次调用中将$.ajax更改为async = false $.getJSON,这似乎解决了语句不执行的问题按照我希望他们的顺序,但它的速度非常慢,无论如何都会因为某些原因而返回undefined ..

有什么建议吗? 我错过了一些非常愚蠢的东西吗?

3 个答案:

答案 0 :(得分:1)

  

似乎getAccordionBody()函数在将html字符串添加到DOM之前没有返回

那是对的。你returning the response (html3) from ajax的方式存在缺陷 - 你不能return来自done处理程序。

然而,你可以通过使用promises来解决这个问题。每个函数都返回一个promise,以便它们很容易链接,then用于转换数据并获得新的承诺:

$.getJSON(url).then(function(data){
    return $.when.apply($, $.map(data, function(i, json){
        return getAccordionPart(…); //creates the accordion for the given source
    }).then(function() {
        var html1 = "<div class='panel-group' id='manageAccordion'>";
        html1 += Array.prototype.join.call(arguments, "\n");
        html1 += "</div>";
        return html1;
    });
}).done(function(html){
    $('#elementList').html(html);
});

function getAccordionPart(id, parent, count, json){ 
    return getAccordionBody(json).then(function(result) {
        var html2 = "…"; //new string html2 is created and a bunch of stuff added
        html2 += result;
        html2 += "</div></div></div></div>";
        return html2;
    });
}

function getAccordionBody(json) {
    var url = standardUrl + "sources/" + encodeURIComponent(json.elementId) + "/streams";
    return $.getJSON(url).then(function(data) {
        var html3 = "…"; //new string "html3" gets created
        $.each(data, function(i, json) {
            html3 += "<li class='list-group-item'>";
            html3 += json.name;
            html3 += "</li>";
        });
        html3 += "</ul>";
        return html3;
    });
}

答案 1 :(得分:0)

您可以使用延迟/承诺模式 - http://api.jquery.com/deferred.promise/

,而不是使用同步调用
  • 您将需要从生成手风琴功能返回承诺。
  • 您需要排队生成手风琴函数调用。
  • 然后在承诺得到解决时按顺序执行追加业务。

答案 2 :(得分:0)

您必须首先收集全局数组中“getAccordionPart”和“getAccordionBody”(例如:encodeURIComponent(json.elementId))所需的所有内容。像:

var arrIds = [];

$.getJSON(url, function(data){
$.each(data, function(i, json){
    arrIds.push(encodeURIComponent(json.elementId))//collect everything which is required for "getAccordionPart" and "getAccordionBody"
});

然后迭代这个集合,并在任何全局变量中收集这些id的手段主体的所有数据。

var bodyData = {};
$.each(arrIds, function(){
var url = standardUrl + "sources/" + this + "/streams";
$.getJSON(url, function(data) {
    bodyData[this] = data;//collect all the Data for accordian body of these ids
}});

也可以在getAccordionPart中进行更改,例如:

function getAccordionPart(id, parent, count, /*json*/ elementId){ 
//new string html2 is created and a bunch of stuff added
//...
html2 += "...."; 
html2 += getAccordionBody(elementId);
html2 += "</div></div></div></div>";
return html2
}

也改变了getAccordionBody:

    function getAccordionBody(/*json*/ elementId){
//new string "html3" gets created
//...

 var data = bodyData[elementId];
    $.each(data, function(i, json) {
        html3 += "<li class='list-group-item'>";
        html3 += json.name;
        html3 += "</li>";
    });
html3 += "</ul>";
    return html3;
}

您的通话也将更改:

$.each(arrIds , function(){
    html1 += getAccordionPart(,,,this); //creates the accordion for the given source
});

你最终的代码将是:

var arrIds = [];

$.getJSON(url, function(data){
$.each(data, function(i, json){
    arrIds.push(encodeURIComponent(json.elementId))//collect everything which is required for "getAccordionPart" and "getAccordionBody"
});

var bodyData = {};
$.each(arrIds, function(){
var url = standardUrl + "sources/" + this + "/streams";
$.getJSON(url, function(data) {
    bodyData[this] = data;//collect all the Data for accordian body of these ids
}});

function getAccordionPart(id, parent, count, /*json*/ elementId){ 
    //new string html2 is created and a bunch of stuff added
    //...
    html2 += "...."; 
    html2 += getAccordionBody(elementId);
    html2 += "</div></div></div></div>";
    return html2
    }

function getAccordionBody(/*json*/ elementId){
//new string "html3" gets created
//...

 var data = bodyData[elementId];
    $.each(data, function(i, json) {
        html3 += "<li class='list-group-item'>";
        html3 += json.name;
        html3 += "</li>";
    });
html3 += "</ul>";
    return html3;
}

$.each(arrIds , function(){
    html1 += getAccordionPart(,,,this); //creates the accordion for the given source
});