用于在文件FileReader上循环的JavaScript [英] JavaScript for loop on files FileReader
问题描述
在我的html文件中的
< script>
标记中,我有这个:pre>
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 ='gray';
document.body.appendChild(img);
var reader = new FileReader();
reader.onload = function(){
img.src = reader.result;
}
reader.readAsDataURL(file);
}
返回false;
}
但是当我在浏览器上放几个图像文件时,只有最后一个图像文件被加载并显示在最后一个img元素中,其他人保持灰色。
正如@chazsolo提到的:
有一种感觉,这是由于你在循环中使用了img。由于reader.onload是异步的,for循环已经完成,img指向最后一个
你可以通过使用 let
而不是 var
循环内(let - MDN)。这将在循环中给出每个 img
和 reader
一个块范围,允许异步读取器方法仍然访问实际
window.ondragover = function(e){return false;}
窗口。 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 ++){
let img = document.createElement('img');
img.height = 200;
img.width = 200;
img.style.background ='gray';
document.body.appendChild(img);
let reader = new FileReader();
reader.onload = function(){
img.src = reader.result;
}
reader.readAsDataURL(file);
}
返回false;
更新:var vs let
那么为什么在 var
中不能正常工作呢?
我尝试用几个实际的例子来解释 let
和 var
的区别。
$ b
变量声明,无论发生什么,都会在任何
代码执行之前处理。
这会引导我们看下面的例子(不要介意最后的错误,这是由剪切插件产生的):
使用var声明
/ **在这个例子中,'a'在使用之后被声明。这并不重要,因为在运行代码之前会处理a的声明。这意味着a被初始化为'undefined',但是是有效的。另外,范围在于执行上下文,这就是为什么它甚至可以在循环外部使用。 ** / console.log(---------); console.log(Example Declare var); console.log(---------); for var i = 0; i <2; i ++){console.log(a); //第一次运行时声明但未定义,之后重新声明并拥有最后一次运行的值。 var a = i;} console.log(a);我们可以看到,在每一个重新声明
保存前code> a a
的值。这不是一个新的实例。
那么,如果我们在循环中使用异步函数,会发生什么?
<使用var 的异步函数
/ **这个例子显示你的影响,如果你在一个循环内使用异步函数。由于循环将在100毫秒(即异步函数的时间)之外被执行,所以对于异步方法的所有执行,c将具有相同的值,这是循环的最后一次运行分配的值。 * / 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会重新声明,因此c会被下一个循环修改,直到最后一个循环。},100);}
$ p确切地说,总是有相同的输出(适应你的问题,总是和img元素和文件一样) 让我们来看看 let
让声明
引发了很多异常,因为 let
具有更具体的范围。最后,我们看到当我们使用 let
和一个异步函数时会发生什么
使用let的异步函数
/ **如果在循环中使用异步函数,则此示例显示效果。由于循环将在100毫秒(这是异步函数的时间)之外执行。让循环的每一次运行都声明一个新的变量,这将会被即将到来的运行所触发。** / 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不重新声明,因此d不会被下一个循环修改},100);}
结论 你总是会得到最后分配的 img
元素和最后分配的文件
。你做了多次相同的操作,你只有最后一个文件在你的数组中。
The problem is breaking my mind. Can someone help me?
In the <script>
tag in my html file I have this:
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;
}
but when I drop several image files on the browser, only the last image file is loaded and displayed in the last img element, others stay grey.
As @chazsolo mentioned:
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
You can fix this by using let
instead of var
within the loop (let - MDN). This will give each img
and reader
a block scope within the loop, allowing the async reader method to still access the actual value from that specific loop run.
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;
}
Update: var vs let
So why is it not working as suspected with var
?
I try to explain the difference of let
and var
with a few practical examples.
Variable declarations, wherever they occur, are processed before any code is executed.
This leads us to the following example (don't mind the error in the end, which is produced by the snipped plugin):
Declaration with var
/**
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.
We see, that on every re declaration of a
the value of the a
before, is kept. It is not a new "instance".
So what's happening if we use a async function within the loop?
Async function with 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);
}
Exactly, always the same output (adapted to your problem, always the same img element and file)
Let's see what's happening with let
Declaration with 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");
A lots of exceptions are thrown, as let
has a more specific scope. Which leads to more intentional coding.
Finally, we see what happens when we use let
and a async function within the loop.
Async function with 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);
}
Conclusion
In your example, you always end up with the last assigned img
element and the last assigned file
. Your doing the same operation as many times as you have file in your array for the only the last file.
这篇关于用于在文件FileReader上循环的JavaScript的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!