【问题标题】:Asynchronous execution of javascript codejavascript代码的异步执行
【发布时间】:2012-06-28 06:47:26
【问题描述】:

我正在学习 javascript 和 json,但我有一些问题:我有一个适用于 json 的脚本,但我写的东西的性能并不是那么好。代码只有在我使用 firebug 或其他工具逐步调试时才有效,这让我认为代码的执行(或代码的一部分......如您将看到的创建表的那个)需要时间太长,以至于浏览器将其停止。

代码是:

var arrayCarte = [];
var arrayEntita = [];
var arraycardbyuser = [];

function displayArrayCards() {
var richiestaEntity = new XMLHttpRequest();

richiestaEntity.onreadystatechange = function() {
    if(richiestaEntity.readyState == 4) {
        var objectentityjson = {};
        objectentityjson = JSON.parse(richiestaEntity.responseText);

        arrayEntita = objectentityjson.cards;
    }
}
richiestaEntity.open("GET", "danielericerca.json", true);
richiestaEntity.send(null);

for(i = 0; i < arrayEntita.length; i++) {

    var vanityurla = arrayEntita[i].vanity_urls[0] + ".json";
    var urlrichiesta = "http://m.airpim.com/public/vurl/";

    var richiestaCards = new XMLHttpRequest();
    richiestaCards.onreadystatechange = function() {
        if(richiestaCards.readyState == 4) {
            var objectcardjson = {};
            objectcardjson = JSON.parse(richiestaCards.responseText);


            for(j = 0; j < objectcardjson.cards.length; j++)
            arrayCarte[j] = objectcardjson.cards[j].__guid__; //vettore che contiene i guid delle card

            arraycardbyuser[i] = arrayCarte;

            arrayCarte = [];
        }
    }
    richiestaCards.open("GET", vanityurla, true);
    richiestaCards.send(null);
}





var wrapper = document.getElementById('contenitoro');

wrapper.innerHTML = "";

var userTable = document.createElement('table');

for(u = 0; u < arrayEntita.length; u++) {
    var userTr = document.createElement('tr');

    var userTdcard = document.createElement('td');
    var userTdinfo = document.createElement('td');

    var br = document.createElement('br');

    for(c = 0; c < arraycardbyuser[u].length; c++) {
        var cardImg = document.createElement('img');
        cardImg.src = "http://www.airpim.com/png/public/card/" + arraycardbyuser[u][c] + "?width=292";
        cardImg.id = "immaginecard";
        userTdcard.appendChild(br);
        userTdcard.appendChild(cardImg);

    }

    var userdivNome = document.createElement('div');
    userdivNome.id = "diverso";
    userTdinfo.appendChild(userdivNome);

    var userdivVanity = document.createElement('div');
    userdivVanity.id = "diverso";
    userTdinfo.appendChild(userdivVanity);

    var nome = "Nome: ";
    var vanityurl = "Vanity Url: ";
    userdivNome.innerHTML = nome + arrayEntita[u].__title__;
    userdivVanity.innerHTML = vanityurl + arrayEntita[u].vanity_urls[0];

    userTr.appendChild(userTdcard);
    userTr.appendChild(userTdinfo);
    userTable.appendChild(userTr);
}

wrapper.appendChild(userTable);
}

问题在于,应该制作表格的代码不会等待与 json 文件一起使用的代码的完整执行。我该如何解决?如果可能的话,我宁愿用简单的方法解决这个问题,没有 jquery 和回调(我是初学者)。

【问题讨论】:

    标签: javascript ajax asynchronous time-complexity


    【解决方案1】:

    您必须移动 som 代码才能使其正常工作。首先,将其拆分为一些功能,然后使用起来更容易。我不知道它是否有效,但想法是首先它加载arrayEntita。完成后,它会填充其他 2 个数组。当最后一个数组被填满时,它会构建表格。

     var arrayCarte = [];
     var arrayEntita = [];
     var arraycardbyuser = [];
     function displayArrayCards() {
        var richiestaEntity = new XMLHttpRequest();
            richiestaEntity.onreadystatechange = function () {
                 if (richiestaEntity.readyState == 4) {
                 var objectentityjson = {};
                 objectentityjson = JSON.parse(richiestaEntity.responseText);
    
                  arrayEntita = objectentityjson.cards;
                  BuildArrayEntita();
                }
            }
            richiestaEntity.open("GET", "danielericerca.json", true);
            richiestaEntity.send(null);
        }
    
        function BuildArrayEntita() {
            for (i = 0; i < arrayEntita.length; i++) {
    
                var vanityurla = arrayEntita[i].vanity_urls[0] + ".json";
                var urlrichiesta = "http://m.airpim.com/public/vurl/";
    
                var richiestaCards = new XMLHttpRequest();
                richiestaCards.onreadystatechange = function () {
                    if (richiestaCards.readyState == 4) {
                        var objectcardjson = {};
                        objectcardjson = JSON.parse(richiestaCards.responseText);
    
    
                        for (j = 0; j < objectcardjson.cards.length; j++)
                            arrayCarte[j] = objectcardjson.cards[j].__guid__; //vettore che contiene i guid delle card
    
                        arraycardbyuser[i] = arrayCarte;
    
                        arrayCarte = [];
                        //If it is the last call to populate arraycardbyuser, build the table:
                        if (i + 1 == arrayEntita.length)
                            BuildTable();
                    }
                }
                richiestaCards.open("GET", vanityurla, true);
                richiestaCards.send(null);
            }
        }
    
    
    
        function BuildTable() {
            var wrapper = document.getElementById('contenitoro');
    
            wrapper.innerHTML = "";
    
            var userTable = document.createElement('table');
    
            for (u = 0; u < arrayEntita.length; u++) {
                var userTr = document.createElement('tr');
    
                var userTdcard = document.createElement('td');
                var userTdinfo = document.createElement('td');
    
                var br = document.createElement('br');
    
                for (c = 0; c < arraycardbyuser[u].length; c++) {
                    var cardImg = document.createElement('img');
                    cardImg.src = "http://www.airpim.com/png/public/card/" + arraycardbyuser[u][c] + "?width=292";
                    cardImg.id = "immaginecard";
                    userTdcard.appendChild(br);
                    userTdcard.appendChild(cardImg);
    
                }
    
                var userdivNome = document.createElement('div');
                userdivNome.id = "diverso";
                userTdinfo.appendChild(userdivNome);
    
                var userdivVanity = document.createElement('div');
                userdivVanity.id = "diverso";
                userTdinfo.appendChild(userdivVanity);
    
                var nome = "Nome: ";
                var vanityurl = "Vanity Url: ";
                userdivNome.innerHTML = nome + arrayEntita[u].__title__;
                userdivVanity.innerHTML = vanityurl + arrayEntita[u].vanity_urls[0];
    
                userTr.appendChild(userTdcard);
                userTr.appendChild(userTdinfo);
                userTable.appendChild(userTr);
            }
    
            wrapper.appendChild(userTable);
        }
    

    我不知道这个检查是否:

    if (i + 1 == arrayEntita.length)
        BuildTable();
    

    但是你必须在执行 buildtable() 之前检查所有响应是否已经返回;

    【讨论】:

    • 我正在尝试,但如果我从 displayArrayCards 调用 BuildArrayEntita(就像你所做的那样)它不起作用(这就是为什么我没有使用不同的函数,而是将所有代码放在一个方法中)。
    • 什么不起作用?您是否尝试检查您的 objectentityjson.cards 以确保它包含您期望它包含的内容。尝试输入 console.log("--unique text--");在每个方法的开始(以及 onreadystatechange 函数中)。然后就可以看到执行顺序了。
    • 我在这里和那里有一些警报,以了解发生了什么,但我看不到其中之一。
    • 乍一看似乎按钮不记得功能
    • 我认为 console.log 更好,因为 alert 会暂停代码并为服务器调用留出更多时间来完成,其中 console.log 将消息添加到日志并继续执行。
    【解决方案2】:

    AJAX 请求是异步的。它们在执行期间到达一个未知的时间段,并且 JavaScript 在继续之前不会等待服务器回复。有同步 XHR,但不适合使用。如果你这样做,你会失去 AJAX 的全部概念。

    通常要做的是传入一个“回调”——一个稍后执行的函数,具体取决于您希望它执行的时间。在您的情况下,您希望在收到数据后生成表格:

    function getData(callback){
        //AJAX setup
        var richiestaEntity = new XMLHttpRequest();
    
        //listen for readystatechange
        richiestaEntity.onreadystatechange = function() {
    
            //listen for state 4 and ok status (200)
            if (richiestaEntity.readyState === 4 && richiestaEntity.status === 200) {
    
                //execute callback when data is received passing it
                //what "this" is in the callback function, as well as
                //the returned data
                callback.call(this,richiestaEntity.responseText);
            }
        }
        richiestaEntity.open("GET", "danielericerca.json"); //third parameter defaults to true
        richiestaEntity.send();
    }
    
    function displayArrayCards() {
    
        //this function passed to getData will be executed
        //when data arrives
        getData(function(returnedData){
    
            //put here what you want to execute when getData receives the data
            //"returnedData" variable inside this function is the JSON returned
    
        });
    }
    

    【讨论】:

    • 只有在第一个 json 的工作完成后,第二个 json 上的代码才有效。所以我也应该处理第二个json,然后做表格。我应该把第二个请求的执行放在函数 getData(callback) 的 if 中?
    • @user1453638 如果它依赖于第一组获取的数据,则您必须在第一个 getData 中执行另一个 getData。另一方面,您可能需要重组数据。多个 AJAX 调用也不理想。如果可能,请在一个电话中完成。
    【解决方案3】:

    一旦您进行了 ajax 调用,请将所有其余代码放入 readystatechange 函数中。这样,它将按顺序执行所有操作。

    编辑:@Dappergoat 解释得比我好。

    【讨论】: