繁体   English   中英

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

[英]Sequence of execution in for loop / recursion

我是最近才了解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 ms,然后将iCounter增大1,然后在iCounter <2时重复for循环。要总结结果集,应包含:iCounter = 0,位置24,offset = 0,offset =- 25,位置42,偏移量= 0,偏移量= -25,位置19,偏移量= 0,偏移量= -25,等待1000ms,iCounter = 1,位置24,偏移量= 0,偏移量= -25等,而iCounter <2 。

非常感激。

没错,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>");

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

要再次重申和扩展我的评论:while和for循环是同步的(按顺序发生)然而, getWeatherInfo函数中的几个语句是异步的(按顺序发生getWeatherInfo )。 这是关于同步与异步JavaScript的非常基本的入门 更具体地说, $.getJSON$.each函数都是异步的。 基本上,只要解析器到达$.getJSON函数, getWeatherInfo函数就会返回,并且for循环的下一次迭代将继续。 同样, $.each函数的所有迭代都“一次性全部触发”(从技术上讲不是正确的,但从概念上讲),并且可以按任何顺序完成。

只要将特定位置的位置信息(包括其偏移量)聚集在一起,这些位置的顺序就不会真正困扰我。 知道我该如何实现吗?

我建议您更改数据结构,并使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,但这是另一个问题。 还值得注意的是,尽管我使用“类似数组的”语法(方括号)来访问对象,但这并不意味着该对象是一个数组或可以被视为一个数组。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM