简体   繁体   English

文件 FileReader 的 JavaScript for 循环

[英]JavaScript for loop on files FileReader

The problem is breaking my mind.问题让我心碎。 Can someone help me?有人能帮我吗? In the <script> tag in my html file I have this:在我的 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;
}

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.但是当我将几个图像文件放在浏览器上时,只有最后一个图像文件被加载并显示在最后一个 img 元素中,其他图像文件保持灰色。

As @chazsolo mentioned:正如@chazsolo 提到的:

Have a feeling this is going to be due to your use of img within the loop.感觉这将是由于您在循环中使用了 img。 Since reader.onload is async, the for loop has already completed and img points to the last one由于 reader.onload 是异步的,for 循环已经完成并且 img 指向最后一个

You can fix this by using let instead of var within the loop (let - MDN) .您可以通过在循环(let - MDN)中使用let而不是var来解决此问题。 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.这将为每个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;
}

Update: var vs let更新:var 与 let

So why is it not working as suspected with var ?那么为什么它不能像var所怀疑的那样工作呢? I try to explain the difference of let and var with a few practical examples.我试着用几个实际例子来解释letvar的区别。

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):这将我们引向以下示例(不要介意最后的错误,它是由 snipped 插件产生的):

Declaration with 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.
We see, that on every re declaration of a the value of the a before, is kept. 我们看到,在每次重新声明a时,都会保留a before 的值。 It is not a new "instance". 它不是一个新的“实例”。

So what's happening if we use a async function within the loop?那么如果我们在循环中使用异步函数会发生什么?

Async function with var带有 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)确切地说,总是相同的输出(适应你的问题,总是相同的 img 元素和文件)

Let's see what's happening with let让我们看看let发生了什么

Declaration with 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");
A lots of exceptions are thrown, as let has a more specific scope. 抛出很多异常,因为let具有更具体的范围。 Which leads to more intentional coding. 这会导致更多的故意编码。

Finally, we see what happens when we use let and a async function within the loop.最后,我们看看在循环中使用let和异步函数时会发生什么。

Async function with 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); }

Conclusion结论

In your example, you always end up with the last assigned img element and the last assigned file .在您的示例中,您总是以最后分配的img元素和最后分配的file结束。 Your doing the same operation as many times as you have file in your array for the only the last file.您执行相同操作的次数与数组中唯一的最后一个文件的文件一样多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM