[英]Why does the onload handler fail to properly populate my array?
我需要一個包含blob的數組,所以我的代碼是:
for (var i = 0; i < total; i++) {
var xhr = createXHR();
xhr.open('GET', 'img/tiles/' + zeroFill(i, 4) + '.png', true);
xhr.responseType = 'blob';
xhr.onload = function() {
arr[i] = new Blob([this.response], {type: 'image/png'});
// console.log(arr[i]);
};
xhr.send();
}
當我輸出arr的i位置時,控制台會正確顯示blob(至少說出它的大小)。 如果我嘗試顯示以前的位置,則會得到undefined 。
如果在所有XHR請求都完成后再看一下arr ,控制台將顯示一個奇怪的數組,其中每個位置均未定義 ,而最后一個位置中包含未完成的blob。
這是一個非常常見的錯誤。 在for
循環完成后, onload
處理程序將被調用為long。 這意味着i
的值將是循環結尾處的值,而不是您希望它位於for
循環中間的值。
要解決此問題,您需要以某種形式在閉包中捕獲i
的正確值。 有很多方法可以做到這一點。
這是一種使用自執行函數的方法,該函數在函數參數中捕獲i
的值。 i
的值傳遞給自執行函數,該函數為for
循環的每次迭代創建一個新范圍,然后在該范圍的函數參數中捕獲i
的正確值。 該函數參數在每次調用自執行函數時都唯一存在,因此將保留所需的值,直到將來某個時候onload
處理程序時才需要該值。 外觀如下:
for (var i = 0; i < total; i++) {
var xhr = createXHR();
xhr.open('GET', 'img/tiles/' + zeroFill(i, 4) + '.png', true);
xhr.responseType = 'blob';
(function(index) {
xhr.onload = function() {
arr[index] = new Blob([this.response], {type: 'image/png'});
// console.log(arr[index]);
}
})(i);
xhr.send();
}
您所有的ajax回調都引用外部作用域的相同i
。 這意味着當您的ajax調用完成時,它們都會將數據推送到相同的i
,該total-1
為total-1
。
附帶說明:以前的索引填充為null
只是將數據推入較大索引時JS數組的工作方式。
常見的解決方案是使用閉包,將當前i
值捕獲到新的執行上下文中:
//read comments in the numeric order
xhr.onload = (function(i) {//2. the `i` inside the function now references
//a new `i` independent from the outer `i`
return function(){//3. returns a function handler that executes on xhr.onload
arr[i] = new Blob([this.response], {type: 'image/png'});
console.log(i); //4. logs the IIFE execution context's `i`,
//as it is the closest (inner-most scope chain-wise) `i`
};
}(i)); //1. Passes outer current `i` as argument to this
//Immediately-Invoked Function Expression (IIFE)
可以在此處找到上述代碼的詳細說明。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.