我需要一个包含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。
答案 0 :(得分:2)
这是一个非常常见的错误。在onload
循环完成后,for
处理程序会被调用很长时间。这意味着i
的值将是循环END处的值,而不是您希望它来自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();
}
答案 1 :(得分:1)
所有ajax的回调都引用了外部作用域的i
。这意味着当您的ajax调用完成后,他们都会将数据推送到i
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)
可以找到上述代码的更详细说明here。