JavaScript 对文件 FileReader 进行循环
JavaScript for loop on files FileReader
这个问题让我心碎。有人能帮我吗?
在我的 html 文件的 <script>
标签中,我有这个:
window.ondragover = function(e){return false;}
window.ondragenter = function(e){return false;}
window.ondrop = function(e){
var files = e.target.files || e.dataTransfer.files;
for (var i = 0, file; file = files[i];i++){
var img = document.createElement('img');
img.height = 200;
img.width = 200;
img.style.background = 'grey';
document.body.appendChild(img);
var reader = new FileReader();
reader.onload = function(){
img.src = reader.result;
}
reader.readAsDataURL(file);
}
return false;
}
但是当我在浏览器上放置多个图像文件时,只有最后一个图像文件被加载并显示在最后一个 img 元素中,其他图像文件保持灰色。
正如@chazsolo 提到的:
Have a feeling this is going to be due to your use of img within the loop. Since reader.onload is async, the for loop has already completed and img points to the last one
您可以通过在循环 (let - MDN) 中使用 let
而不是 var
来解决这个问题。这将为每个 img
和 reader
循环内的块范围,允许异步 reader 方法仍然访问来自该特定循环的实际值 运行.
window.ondragover = function(e){return false;}
window.ondragenter = function(e){return false;}
window.ondrop = function(e){
var files = e.target.files || e.dataTransfer.files;
debugger;
for (var i = 0, file; file = files[i];i++){
let img = document.createElement('img');
img.height = 200;
img.width = 200;
img.style.background = 'grey';
document.body.appendChild(img);
let reader = new FileReader();
reader.onload = function(){
img.src = reader.result;
}
reader.readAsDataURL(file);
}
return false;
}
更新:var 与 let
那么为什么它不像 var
所怀疑的那样工作?
我试着用几个实际例子来解释 let
和 var
的区别。
Variable declarations, wherever they occur, are processed before any
code is executed.
这将我们引向以下示例(不要介意最后的错误,它是由 snipped 插件产生的):
用变量声明
/**
In this example, 'a' is declared after it is used. This doesn't matter, as the
declaration of 'a' will be processed before running the code. This means a is
initialized with 'undefined' but is valid. Also the scope of a lies within the
execution context, that's why it is even available outside of the loop.
**/
console.log("---------");
console.log("Example Declaration var");
console.log("---------");
for (var i = 0; i < 2; i++) {
console.log(a); // a is declared but undefined on the 1st run, afterwards it get redeclared and owns the value from the last run.
var a = i;
}
console.log(a); // a is even available out here as still same execution context.
我们看到,在每次重新声明 a
时,都会保留之前 a
的值。这不是新的 "instance".
那么如果我们在循环中使用异步函数会发生什么?
带有 var 的异步函数
/**
This example shows you the effects, if you use a async function within a loop.
As the loop will be executed way under 100 miliseconds (which is the time out
of the async function), c will have the same value for all exections of the
async mehtod, which is the value assigned by the last run of the loop.
**/
console.log("---------");
console.log("Example effects async var");
console.log("---------");
for (var i = 0; i < 2; i++) {
var c = i;
setTimeout(function() {
console.log(c); //var does redeclare, therefor c will be modified by the next loop until the last loop.
}, 100);
}
确切地说,总是相同的输出(适应你的问题,总是相同的 img 元素和文件)
让我们看看 let
发生了什么
带 let 的声明
/**
In this example, 'b' is declared after it is used with let. let will be processed
during runtime. This means 'b' will not be declared when used. This is an invalid
state. let will give a strict context within the loop. It will be not available
outside. let has a similar behavior as a declaration in Java.
**/
console.log("---------");
console.log("Example Declaration let");
console.log("---------");
for (var i = 0; i < 2; i++) {
try {
console.log(b); //b is not declared yet => exception
} catch (ex) {
console.log("Exception in loop=" + ex);
}
let b = i;
console.log("Now b is declared:"+b);
}
try {
console.log(b); // b is not available out here as the scope of b is only the for loop. => exception
} catch (ex) {
console.log("Exception outside loop=" + ex);
}
console.log("Done");
抛出很多异常,因为 let
具有更具体的范围。这导致了更多的有意编码。
最后,我们看看在循环中使用 let
和异步函数时会发生什么。
带 let 的异步函数
/**
This example shows you the effects, if you use a async function within a loop.
As the loop will be executed way under 100 milliseconds (which is the time out
of the async function). let declares a new variable for each run of the loop,
which will be untouched by upcoming runs.
**/
console.log("---------");
console.log("Example effects async let");
console.log("---------");
for (var i = 0; i < 2; i++) {
let d = i;
setTimeout(function() {
console.log(d); //let does not redeclare, therefor d will not be modified by the next loop
}, 100);
}
结论
在您的示例中,您总是以最后分配的 img
元素和最后分配的 file
元素结束。您执行相同操作的次数与数组中的文件一样多,只有最后一个文件。
这个问题让我心碎。有人能帮我吗?
在我的 html 文件的 <script>
标签中,我有这个:
window.ondragover = function(e){return false;}
window.ondragenter = function(e){return false;}
window.ondrop = function(e){
var files = e.target.files || e.dataTransfer.files;
for (var i = 0, file; file = files[i];i++){
var img = document.createElement('img');
img.height = 200;
img.width = 200;
img.style.background = 'grey';
document.body.appendChild(img);
var reader = new FileReader();
reader.onload = function(){
img.src = reader.result;
}
reader.readAsDataURL(file);
}
return false;
}
但是当我在浏览器上放置多个图像文件时,只有最后一个图像文件被加载并显示在最后一个 img 元素中,其他图像文件保持灰色。
正如@chazsolo 提到的:
Have a feeling this is going to be due to your use of img within the loop. Since reader.onload is async, the for loop has already completed and img points to the last one
您可以通过在循环 (let - MDN) 中使用 let
而不是 var
来解决这个问题。这将为每个 img
和 reader
循环内的块范围,允许异步 reader 方法仍然访问来自该特定循环的实际值 运行.
window.ondragover = function(e){return false;}
window.ondragenter = function(e){return false;}
window.ondrop = function(e){
var files = e.target.files || e.dataTransfer.files;
debugger;
for (var i = 0, file; file = files[i];i++){
let img = document.createElement('img');
img.height = 200;
img.width = 200;
img.style.background = 'grey';
document.body.appendChild(img);
let reader = new FileReader();
reader.onload = function(){
img.src = reader.result;
}
reader.readAsDataURL(file);
}
return false;
}
更新:var 与 let
那么为什么它不像 var
所怀疑的那样工作?
我试着用几个实际例子来解释 let
和 var
的区别。
Variable declarations, wherever they occur, are processed before any code is executed.
这将我们引向以下示例(不要介意最后的错误,它是由 snipped 插件产生的):
用变量声明
/**
In this example, 'a' is declared after it is used. This doesn't matter, as the
declaration of 'a' will be processed before running the code. This means a is
initialized with 'undefined' but is valid. Also the scope of a lies within the
execution context, that's why it is even available outside of the loop.
**/
console.log("---------");
console.log("Example Declaration var");
console.log("---------");
for (var i = 0; i < 2; i++) {
console.log(a); // a is declared but undefined on the 1st run, afterwards it get redeclared and owns the value from the last run.
var a = i;
}
console.log(a); // a is even available out here as still same execution context.
a
时,都会保留之前 a
的值。这不是新的 "instance".
那么如果我们在循环中使用异步函数会发生什么?
带有 var 的异步函数
/**
This example shows you the effects, if you use a async function within a loop.
As the loop will be executed way under 100 miliseconds (which is the time out
of the async function), c will have the same value for all exections of the
async mehtod, which is the value assigned by the last run of the loop.
**/
console.log("---------");
console.log("Example effects async var");
console.log("---------");
for (var i = 0; i < 2; i++) {
var c = i;
setTimeout(function() {
console.log(c); //var does redeclare, therefor c will be modified by the next loop until the last loop.
}, 100);
}
确切地说,总是相同的输出(适应你的问题,总是相同的 img 元素和文件)
让我们看看 let
带 let 的声明
/**
In this example, 'b' is declared after it is used with let. let will be processed
during runtime. This means 'b' will not be declared when used. This is an invalid
state. let will give a strict context within the loop. It will be not available
outside. let has a similar behavior as a declaration in Java.
**/
console.log("---------");
console.log("Example Declaration let");
console.log("---------");
for (var i = 0; i < 2; i++) {
try {
console.log(b); //b is not declared yet => exception
} catch (ex) {
console.log("Exception in loop=" + ex);
}
let b = i;
console.log("Now b is declared:"+b);
}
try {
console.log(b); // b is not available out here as the scope of b is only the for loop. => exception
} catch (ex) {
console.log("Exception outside loop=" + ex);
}
console.log("Done");
let
具有更具体的范围。这导致了更多的有意编码。
最后,我们看看在循环中使用 let
和异步函数时会发生什么。
带 let 的异步函数
/**
This example shows you the effects, if you use a async function within a loop.
As the loop will be executed way under 100 milliseconds (which is the time out
of the async function). let declares a new variable for each run of the loop,
which will be untouched by upcoming runs.
**/
console.log("---------");
console.log("Example effects async let");
console.log("---------");
for (var i = 0; i < 2; i++) {
let d = i;
setTimeout(function() {
console.log(d); //let does not redeclare, therefor d will not be modified by the next loop
}, 100);
}
结论
在您的示例中,您总是以最后分配的 img
元素和最后分配的 file
元素结束。您执行相同操作的次数与数组中的文件一样多,只有最后一个文件。