2016-12-28 35 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