用于在文件FileReader上循环的JavaScript [英] JavaScript for loop on files FileReader

查看:141
本文介绍了用于在文件FileReader上循环的JavaScript的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题在打破我的想法。有人能帮我吗?
在我的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);}

让我们来看看 let



让声明

与let一起使用。让我们在运行时进行处理。这意味着'b'在使用时不会被声明。这是一个无效的状态。让循环内部给予严格的上下文。这将不会在外面提供。让我们在Java中声明一个类似的行为。** / console.log(---------); console.log(Example Decla let); console.log(--- ------); for(var i = 0; i <2; i ++){try {console.log(b); // b尚未声明=> catch(ex){console.log(Exception in loop =+ ex); }让b = i; console.log(现在b被声明:+ b);} try {console.log(b); // b在这里是不可用的,因为b的范围只是for循环。 => catch(ex){console.log(Exception outside loop =+ ex);} console.log(Done);


引发了很多异常,因为 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆