0

I've this function in a module for to load a files as base64 and its attributes:

function getFiles(obj, type) {
  let destinazione = type;
  let files = obj.files;
  let imagesDocs = [];
  files.forEach(file => {
    let reader = new FileReader();
    reader.onload = function(ev) {
      let result = this.result;
      let f = {
        name: file.name,
        size: file.size,
        type: file.type,
        data: result
      };
      imagesDocs.push(f);
    };
    reader.readAsDataURL(file);
  });
  return imagesDocs;
}

export default getFiles;

In another module, I import fileArray module and use it as:

const resultArray = getFiles(e.target, type);
let newArray = [...resultArray];
console.log(newArray);

console.log show me an empty array, while resultArray contain more objects.

I tried too with:

let numbers = [1, 2, 3, 4];
let newnumbers = [...numbers];

and work fine.

Why?

Update:

Using the Anson Miu's code I resolved. The "files" variable, being filelist type must be converted to array type. I did it with [...files].

Thanks to all.

Kraken
  • 111
  • 11
  • You export fileArray but there is no array called fileArray in that file? – PixAff Apr 05 '21 at 17:06
  • 1
    It's because none of the stuff in reader.onload has happened at the point that you try to log newArray. – James Apr 05 '21 at 17:08
  • @PixAff I corrected it – Kraken Apr 05 '21 at 17:16
  • @James console.log(resultArray) show mi this: [] 0: {name: "2257081.jpg", size: 77830, type: "image/jpeg", data: "data:image/jpeg;base64,/9j/4AAQSkZJR"} length: 1 __proto__: Array(0) – Kraken Apr 05 '21 at 17:19
  • console.log is kind of async, though, so you don't see the data as it was when the console.log happened. https://stackoverflow.com/questions/23392111/console-log-async-or-sync – James Apr 05 '21 at 17:23
  • @James thanks. Then I must to manage the asynchronius file loading – Kraken Apr 05 '21 at 17:38

3 Answers3

1

The problem is that reader.onload is an asynchronous process.

What happens is that you loop through all the files, then you pass the empty result (imagesDocs) back, and then sometime later populate imagesDocs.

you need to handle the process asynchronously, using callback, async/await and/or promises.

Daniel
  • 34,125
  • 17
  • 102
  • 150
1

reader.onload is an asynchronous callback, so it is possible that the imageDocs array is not populated when you return from your getFiles function.

I suggest to extract the logic for reading a file into a separate function that returns a Promise:

function readFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = function(ev) {
      const result = this.result;
      resolve({
        name: file.name,
        size: file.size,
        type: file.type,
        data: result,
      });
    };

    reader.readAsDataURL(file);
  });
}

Then update getFiles to be an asynchronous function that maps the files to Promises and returns a Promise that resolves to the imageDocs:

async function getFiles(obj, type) {
  const destinazione = type;
  const files = obj.files;
  const imageDocs = await Promise.all(files.map(readFile));
  return imageDocs;
}
Anson Miu
  • 1,171
  • 7
  • 6
  • It return: "Uncaught (in promise) TypeError: files.map is not a function" – Kraken Apr 05 '21 at 17:35
  • From your OP it seems that `files` is iterable - you can use `Array.from(files)` to convert it into an array (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) – Anson Miu Apr 05 '21 at 18:46
0

I think you need to

export default getFiles;
PixAff
  • 309
  • 4
  • 14