JavaScript for for file on files FileReader

Sta*_*lev 2 javascript for-loop filereader

问题是我的想法.有人能帮我吗?在<script>我的html文件的标签中,我有这个:

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;
}
Run Code Online (Sandbox Code Playgroud)

但是当我在浏览器上删除多个图像文件时,只加载最后一个图像文件并显示在最后一个img元素中,其他图像文件保持灰色.

Her*_*erb 7

正如@chazsolo所说:

感觉这是由于你在循环中使用img.由于reader.onload是异步的,for循环已经完成,img指向最后一个

您可以通过使用let而不是var在循环内(let-MDN)来解决此问题.这将在循环中给出每个imgreader一个块范围,允许异步读取器方法仍然访问该特定循环运行的实际值.

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;
}
Run Code Online (Sandbox Code Playgroud)

更新:var vs let

那么为什么它不像怀疑那样工作var?我试图解释的差异let,并var有一些实际的例子.

变量声明,无论它们出现在何处,都会在执行任何代码之前进行处理.

这引出了以下示例(不介意最后的错误,这是由剪切的插件产生的):

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.
Run Code Online (Sandbox Code Playgroud)
我们看到,在每次重新宣布之前a的价值时a,都会保留.它不是一个新的"实例".

那么如果我们在循环中使用异步函数会发生什么?

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);
}
Run Code Online (Sandbox Code Playgroud)

确切地说,总是相同的输出(适应你的问题,总是相同的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");
Run Code Online (Sandbox Code Playgroud)
抛出了许多异常,因为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);
}
Run Code Online (Sandbox Code Playgroud)

结论

在您的示例中,您始终以最后分配的img元素和最后分配的元素结束file.您执行相同操作的次数与数组中的文件一样多,仅用于最后一个文件.