1

What i've been trying to do is add the files and their matching dataurl into objects in an array.

Files is a FileList object.

I first tried this inside the onloadend event of the Filereader but couldn't access the original file during reading so moved onto promises.

var data = [];
for(var i = 0; i < files.length; i++){
   data.push({
        file: files[i],   //keep the files for uploading
        src: readFile(files[i]) // generate the src to offer preview image
    });
    var last = data.length -1;
    console.log(last); //log a
    data[last].src.then(function(result){
        console.log(last); // log b
        data[last].src = result // overwrite the src deffered object with the result of the promise
    });
}

readFile is returning a deferred promise, assume this to be working.

this is working fine when files has a length of 1 but when files is multiple im having issues with the asynchronous side of things and it only working for the last item.

Result of logs based on 2 files (files.length == 2):

0 //log a
1 //log a
1 //log b <-- ignores 0 stays as 1
1 //log b

expecting 0101

Kiee
  • 10,661
  • 8
  • 31
  • 56
  • 1
    This is an issue with looping and closures which has been answered here before, see, for example, http://stackoverflow.com/q/750486/623518 and http://stackoverflow.com/q/27254735/623518. – Chris Jan 27 '15 at 21:50
  • 1
    You really should use `Promise.all` instead of manually assigning or even overwriting things anywhere. Btw, `data[last]` is the object literal with `file` and `src` properties, and does not have a `then` method? – Bergi Jan 27 '15 at 22:10
  • You are correct I missed out src when extracting an example of code. I'll have a look at .all, im still fairly new to promises. – Kiee Jan 27 '15 at 22:17

1 Answers1

2

This is a common problem: JavaScript closure inside loops – simple practical example.

You can solve it by binding the index to the callback:

data[last].then(function(index, result){
    data[index].src = result;
}.bind(null, last));
Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Thank you, this has worked but could you tell me where index has come from, and why you're passing null into the bind? – Kiee Jan 27 '15 at 21:59
  • `.bind` returns a new function and passes the second and further arguments to that function. So `index` is passed the value of `last`. The first argument of `.bind` is the value `this` gets bound to. But since we don't need to bind `this` to a specific value, I just passed `null`. Learn more about `.bind` here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind – Felix Kling Jan 27 '15 at 22:06