2016-12-28 36 views
1

下面是成功加载所有五个图片代码:for循环中的Ajax调用在表达为函数时起作用,但不在for循环中直接放置时起作用。为什么?

for(i=0; i<5; i++) { 
    (function() { 
    var oReq = new XMLHttpRequest(); 
    var r = "images/"+i+".jpg"; 
    oReq.open("GET",r, true); 
    oReq.responseType = "arraybuffer"; 
    oReq.send(); 

    oReq.onload = function(oEvent) { 
     var blob = new Blob([oReq.response], {type: "image/jpg"}); 
     var x = window.URL.createObjectURL(blob); 
     var img = new Image(); 
     img.src = x; 
     img.width = 100; 
     $("#someDiv").append(img); 
     }; 
    })(); 
} 

这里是代码,只加载最后一个图像:

for(i=0; i<5; i++) { 
    var oReq = new XMLHttpRequest(); 
    var r = "images/"+i+".jpg"; 
    oReq.open("GET",r, true); 
    oReq.responseType = "arraybuffer"; 
    oReq.send(); 

    oReq.onload = function(oEvent) { 
     var blob = new Blob([oReq.response], {type: "image/jpg"}); 
     var x = window.URL.createObjectURL(blob); 
     var img = new Image(); 
     img.src = x; 
     img.width = 100; 
     $("#someDiv").append(img); 
    }; 
} 

为什么回调异步函数在for循环只有当代码被放置在函数中而不是直接放置在循环中时才能工作?

+3

因为调用一个函数会创建一个新的作用域,给每个回调“自己的”oReq变量。请参见[JavaScript闭合内部循环 - 简单实例](http://stackoverflow.com/q/750486/218196)。如果没有它,'oReq'将始终引用最后一次迭代的值,因此'新Blob([oReq.response],{type:“image/jpg”});'总是收到最后一次请求的响应。 –

+0

在ES6中注意,您可以通过使用'let'而不是'var'在循环中声明所有变量来获得所需的行为。这也适用于相同的原因 - 每次关闭一个新变量而不是在每次迭代中捕获同一个变量。 – PMV

+1

其原因在于“变量的范围”。当你将变量放在函数中时(就像你的情况一样),每个变量都有自己的作用域(你的函数在循环中),但是当你直接使用它时,它会覆盖同一个变量新的价值..结果你有最后的价值作为结果 – RohitS

回答

2

在第一种情况中,有尽可能多的变量oReq作为有所述循环的迭代,因为每个包装功能被调用时((function() {...})()),它创建一个新的范围,包括一个新的oReq变量。

在第二种情况下,有一个oReq变量重复使用,并在循环的每次迭代中设置为一个新值。

这很重要,因为它确定oReqonload处理程序中执行new Blob([oReq.response], ...);时引用的值。在第一种情况下,它指的是匿名包装功能本地的oReq,因此每个onload函数指的是唯一的oReq。在第二种情况下,所有onload回调指的是单个oReq值,其中存储单个最终值oReq

+0

谢谢:)好的解释! –

+0

那么,为什么它不是所有五次追加'oReq.response'的最终值而不是5次出错? – Desdemona

+0

@Desdemona它在你的浏览器的JS控制台中产生了什么错误信息? – apsillers