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.
imgwithin the loop. Sincereader.onloadis async, the for loop has already completed andimgpoints to the last oneimgis asigned to a new element and then itssrcis asigned toresultsof newreaderthat was created in the same loop. next loop:imgvar is reasigned to a new element and itssrcis asigned to theresultof another newreader. is it wrong?