javascriptes6-promisefilereaderasynchronous-javascript

Empty result using FileReader and promise


I am struggling a bit with asynchronous operations and Promises (a quite new concept to me) using FileReader. I have found a very interesting thread about it there, but can't make my script to work despite this great content.

I have a file input accepting multiple files, I want to read those files and push their content into an array. But it seems I am not quite understanding well how a promise works because I still get an empty array at the end.

const inputElement = document.getElementById("trackfiles");
inputElement.addEventListener("change", (e) => {
  const selectedFiles = inputElement.files;

  let p = Promise.resolve();
  for (const file of selectedFiles) {
    p = p.then(() =>
      readAsData(file).then((content) => {
        files_content.push(content);
      }),
    );
  }

  console.log(files_content);
});

function readAsData(file) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();
    reader.readAsText(file);
    reader.onload = () => {
      resolve(reader.result);
    };
    reader.onerror = reject;
  });
}

When I select files, I get an empty array:

Chrome dev tools log

Thank you for your help


Solution

  • You are printing the array before the asynchronous then callbacks have executed.

    You need to await the resolution of the promises before printing the array.

    So replace this:

      console.log(files_content);
    

    with this:

      p.then(() => console.log(files_content));
    

    Unrelated to your question, but you don't have to wait to have read one file before starting to read the next. You could call readAsData for all selected files without delay, and then await all promises you get returned for them with Promise.all.

    Secondly, things may look cleaner when you make use of the async/await syntax:

    inputElement.addEventListener("change", async (e) => {
      const files_content = await Promise.all(Array.from(inputElement.files, readAsData));
      console.log(files_content);
    });