我最近才了解到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。
非常感谢。
答案 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