下面的函数应该为每个查询获取视频,并构建一些依赖于i
的html
function getVideos() {
var text = "";
for(var i=0; i<queryArray.length; i++){
var queryUrl = "http://gdata.youtube.com/feeds/api/videos?q="+queryArray[i]+
"&max-results=1&orderby=relevance&v=2&alt=json&format=5";
$.get(queryUrl, function(data){
constructHtml(data, i);
}, 'json');
}
}
然而,每次调用$.get
时,它都会将i
作为2
传递给constructHtml,这是为什么?注意:querryArray
中有两个值,因此"2"
在技术上是越界的。
由于$.get()
的默认异步特性,for循环将继续执行,i变量将被重新分配。
解决此问题的快速方法是在$.get()
上设置async: false
,这将从根本上阻止for循环继续执行,直到$.get()
完成,这意味着i
的值在此过程中不会更改。
但必须强调的是,这将阻止所有脚本在页面上执行,直到for循环完成,这可能会在很长一段时间内阻止用户完成其他操作。
因为在调用回调方法时,for
循环已经执行完毕,并且i
被设置为数组中的最高索引+1。值为2(即使只有2个项),因为i++
的执行次数比数组中的项多1次。
试试这个:
function(index) {
$.get(queryUrl, function(data){
constructHtml(data, index);
}, 'json');
}(i);
代码不起作用的原因是回调在循环完成时执行。因此,您可以启动两个或多个AJAX操作,但当它们完成时,"i"现在是循环的结束。
这是可变吊装;变量总是被提升到函数范围,即使您在块中定义它们也是如此。
您定义的内联函数正在"关闭"对i的引用,因此在调用constructHtml时,它是最后一个值。尝试将其定义为更高范围的函数,并传递参数。
阅读:
http://oreilly.com/javascript/excerpts/javascript-good-parts/awful-parts.html
这是因为AJAX调用是异步的,所以当成功回调运行时,循环已经结束,i
的值就是循环结束时得到的值。
使用闭包为每次迭代保留i
的值:
function getVideos() {
var text = "";
for(var i=0; i<queryArray.length; i++){
(function(index){
var queryUrl = "http://gdata.youtube.com/feeds/api/videos?q="+queryArray[index]+
"&max-results=1&orderby=relevance&v=2&alt=json&format=5";
$.get(queryUrl, function(data){
constructHtml(data, index);
}, 'json');
})(i);
}
}
下面是一个使用计时器来显示变量值保留用于异步回调的演示:http://jsfiddle.net/Guffa/WgxPC/