0

I am loading some files form my server via XMLHttpRequest. The loaded files should then be pushed onto an Array object so that I can process them. Here is my code:

var fileList = [];

angular.forEach(images, function(image, key) {

let xhr = new XMLHttpRequest();

xhr.open('GET', '/img/listings/' + image.dir + '/' + image.name, true);
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.responseType = 'blob';

xhr.send();

xhr.onload = function() {
    if (xhr.status != 200) { // analyze HTTP status of the response
        alert(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found

    } else {
        var blob = new File([this.response], {type: 'image/png'}); 
        fileList[0] = blob; 
    }

};

console.log(fileList);
console.log(fileList.length);

The result of the console log is:

[]
0: File {name: "[object Object]", lastModified: 1569449982337, lastModifiedDate: Wed Sep 25 2019 23:19:42 GMT+0100 (British Summer Time), webkitRelativePath: "", size: 77928, …}
length: 1
__proto__: Array(0)

But the length is 0. Why is the length 0 when it has content.

Jschriemer
  • 625
  • 1
  • 7
  • 23
Alan A
  • 2,557
  • 6
  • 32
  • 54
  • I believe `fileList[0] = blob;` should be `fileList.push(blob);` – Tigger Sep 25 '19 at 22:27
  • Take a look here: https://stackoverflow.com/questions/6355382/javascript-array-not-returning-the-correct-length Simply said it calculate length before asynchronous call is finished. – N. Djokic Sep 25 '19 at 22:27
  • @Tigger I had already tried push - propblem remains: length: 2 __proto__: Array(0) – Alan A Sep 25 '19 at 22:33

2 Answers2

0

It is because your console.log happens at a different time from when you actually push the blob in your array.

What I mean is that console.log(fileList) receives a reference to the array, which means it will show the current value of the array. So, the value is after you got the file.

However, console.log(fileList.length) obtains the length of the array before you are done obtaining the file. It is not the current value and the one at the time of the console.log. I believe it is because the Number is passed by value and not by reference.

Edit:

For example, if you log your length after this line: fileList[0] = blob; it will show the current length.

Artur
  • 334
  • 5
  • 15
0

There are few little things happening.

First, change this code:

xhr.onload = function() {
    if (xhr.status != 200) { // analyze HTTP status of the response
        alert(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found

    } else {
        var blob = new File([this.response], {type: 'image/png'}); 
        fileList[0] = blob; 
    }
};
console.log(fileList);
console.log(fileList.length);

to

xhr.onload = function() {
    if (xhr.status != 200) { // analyze HTTP status of the response
        alert(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found

    } else {
        var blob = new File([this.response], {type: 'image/png'}); 
        // You wanted to add to the array.
        // Using fileList[0] will overwrite the 0 element/object
        fileList.push(blob);
    }
   //console.log(fileList);
   console.log(fileList.length);
};

And the reason why?

Placing the console.log outside of the AJAX will not work as the AJAX will work on a different thread in the background but the console.log call will be run on main thread. See How do I return the response from an asynchronous call? for a lot more detail.

The other thing you are doing is overwriting your 0 index element of fileList with the fileList[0] = blob;. You will need to change that to fileList.push(blob); to add the object to the array.

Tigger
  • 8,980
  • 5
  • 36
  • 40