for循环/递归中的执行顺序

时间:2016-04-25 21:33:49

标签: javascript jquery

我最近才了解到jquery / javascript,我遇到了以下问题。

我试图控制嵌套循环中的函数调用序列和/或jquery / javascript中的递归。在我看来,现在几乎同时调用所有函数,并且不遵循代码中的顺序,就像我在其他编程语言中习惯的那样,例如R.在R脚本中,代码不会处理下一行,只要当前的代码行未完成。但似乎jquery代码同时触发了所有的getJSON请求,并在1结果可用时立即处理结果。它没有注意getJSON调用的顺序。这是真的吗,还是我错过了什么?刷新几页下面的页面会给我不同顺序的结果集,而一次又一次地预期相同的顺序......

为了解释上述情况,我创建了以下可行代码,该代码使用gridpointweather.com的api进行说明。

<!DOCTYPE html>
<meta charset="utf-8">

<!--Body-->
<body>
    <div id="results"></div>
</body>

<!--Load jquery + uri.js-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/URI.js/1.17.0/URI.min.js"></script>

<script>
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // GLOBAL VARIABLES.
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    var g_asLoc =                         ["24", "42", "19"];
    var g_asWeather =                     [];

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function getWeatherInfo(location, offset){    
        console.log("Location: " + location);
        console.log("Offset: " + offset);
        var sUrl = 'http://api.gridpointweather.com/weather/getjson?location=' + location + '%2C-72&model=gfs.api0.n7m4csjf3x2s92ic&hours=24&inunits=1&interptype=2&offset=' + offset;
        var requestUrl = sUrl;
        $.getJSON(requestUrl, function(data) {
            try {
                console.log("Data for location " + location, data);
            }catch(err) {
                console.log(err);
            }

            // Store something.
            $.each(data.data, function(index, weatherInfo){
                g_asWeather.push("Object " + index + ", Location: " + location + ", rawdate: " + weatherInfo.rawdate + ", Temp: " + weatherInfo.temp + "<br>");
            });

            // Offset with 25 if condition not met.
            if(offset == -25){
                // Display in #results.
                g_asWeather.push("<br><br>");
                $("#results").html(g_asWeather.join('\n'));
                console.log("Finished for location " + location);
                return;
            }else{
                console.log("Running again using offset " + (offset-25) + " for location " + location);
                getWeatherInfo(location, offset - 25);
            }
        }).error(function(){
                console.log("JSON error!");
                return;
        });
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // MAIN
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    var iCounter = 0;
    while(iCounter < 2){
        for(iLoc=0; iLoc<g_asLoc.length; iLoc++){
            getWeatherInfo(g_asLoc[iLoc], 0);
        }
        iCounter = iCounter + 1;
    }
</script>

最好我希望代码为1个位置调用函数getWeatherInfo,然后在继续下一个位置之前完成此位置的递归...递归的顺序也很重要,因为offset = 0的结果应该在g_asWeather中,在offset = 25的结果之前。在完成所有位置之后,代码应该等待,例如1000毫秒,然后在iCounter增加1之前重复for循环,同时iCounter&lt; 2.总结结果集应包含:iCounter = 0,位置24,偏移= 0,偏移= -25,位置42,偏移= 0,偏移= -25,位置19,偏移= 0,偏移= -25,等待1000ms,iCounter = 1,位置24,偏移= 0,偏移= -25等等,而iCounter&lt; 2。

非常感谢。

2 个答案:

答案 0 :(得分:0)

没错,AJAX请求是异步的,因此您不知道每个请求的结束顺序。你可以做的是创建一个数组来保存信息,并使用for循环的索引来排序数据,例如,而不是这样做:

 g_asWeather.push("Object " + index + ", Location: " + location + ", rawdate: " + weatherInfo.rawdate + ", Temp: " + weatherInfo.temp + "<br>");

您可以执行类似的操作(将iLoc作为参数传递):

 g_asWeather[iLoc] = "Object " + index + ", Location: " + location + ", rawdate: " + weatherInfo.rawdate + ", Temp: " + weatherInfo.temp + "<br>");

因此,您的数组将按位置排序,如果您想以其他方式对数组进行排序,只需更改将要存储字符串的变量。

答案 1 :(得分:0)

重申并扩展我的评论: while和for循环是同步的(按顺序发生)但是getWeatherInfo函数中的几个语句是异步的(发生在乱序中)。这是同步和异步javascript上的very basic primer。更具体地说,$.getJSON$.each函数都是异步的。基本上,只要解析器到达$.getJSON函数,getWeatherInfo函数就会返回,for循环的下一次迭代会继续。同样地,$.each函数的所有迭代都会被一次性触发&#39; (技术上不是真的,但在概念上)并且可以按任何顺序完成。

  

地点的顺序并没有真正打扰我,只要   特定位置的位置信息(包括其偏移量)   是聚集的。知道如何才能实现这一目标吗?

我建议更改您的数据结构并使g_asWeather成为一个对象(var g_asWeather = {};而不是var g_asWeather = [];),并将位置作为属性。你的$ .each循环看起来像这样:

// Store something.
$.each(data.data, function(index, weatherInfo){
    g_asWeather[location] = "Object " + index + ", Location: " + location + ", rawdate: " + weatherInfo.rawdate + ", Temp: " + weatherInfo.temp + "<br>";
});

输出结果,如:

var results = '';
for (var location in g_asWeather) {
    // This check is used because of some non-obvious ways that JavaScript can treat
    // objects. http://phrogz.net/death-to-hasownproperty explains both why to 
    // use it and why not to. 
    if (!g_asWeather.hasOwnProperty(location)) continue;

    results += g_asWeather[location] + '\n';
}

$('#results').html(results);

我还建议在循环之外更新DOM,但这是另一个问题。值得注意的是,虽然我正在使用&#34;类似阵列的&#34;用于访问对象的语法(方括号),这并不意味着该对象是一个数组或者可以被视为一个数组。

JavaScript允许一些不同的语法来访问对象属性。您可以使用&#34;点符号&#34;当您通过名称直接访问属性时,或者在将属性名称作为字符串传递时使用方括号。请考虑以下示例:

var foobar = {
    a: 'foo',
    b: 'bar'
};

foobar.a; // 'foo'
foobar['a']; // also 'foo'

foobar.forEach(someCallback); // fails because it's not an array