Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Promises with FileReader()

I have the following HTML Code:

<input type='file' multiple> 

And Here's my JS Code:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){     var fr = new FileReader();     for(var i = 0; i < inputFiles.files.length; i++){         fr.onload = function(){             console.log(i) // Prints "0, 3, 2, 1" in case of 4 chosen files         }     }     fr.readAsDataURL(inputFiles.files[i]); } 

So my question is, how can I make this loop synchronous ? That is first wait for the file to finish loading then move on to the next file. Someone told me to use JS Promises. But I can't make it to work. Here's what I'm trying:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){     for(var i = 0; i < inputFiles.files.length; i++){         var fr = new FileReader();         var test = new Promise(function(resolve, reject){             console.log(i) // Prints 0, 1, 2, 3 just as expected             resolve(fr.readAsDataURL(inputFiles.files[i]));         });         test.then(function(){             fr.onload = function(){                 console.log(i); // Prints only 3             }         });     }; } 

Thanks in advance...

like image 983
Zahid Saeed Avatar asked Dec 28 '15 14:12

Zahid Saeed


People also ask

What does FileReader do in JavaScript?

The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.

Is FileReader async JavaScript?

The FileReader methods work asynchronously but don't return a Promise. And attempting to retrieve the result immediately after calling a method will not work, as the . onload event handler fires only after the FileReader has successfully finished reading the file and updates the FileReader's .

How do I make my reader onload synchronous?

You can use the standard FileReaderSync, which is a simpler, synchronous, blocking version of the FileReader API, similar to what you are already using: let reader = new FileReaderSync(); let result_base64 = reader. readAsDataURL(file); console. log(result_base64); // aGV5IHRoZXJl...


2 Answers

We modified midos answer to get it to work the following:

function readFile(file){   return new Promise((resolve, reject) => {     var fr = new FileReader();       fr.onload = () => {       resolve(fr.result )     };     fr.onerror = reject;     fr.readAsText(file.blob);   }); } 
like image 117
Jens Lincke Avatar answered Sep 21 '22 11:09

Jens Lincke


If you want to do it sequentially( not synchronously) using Promises, you could do something like:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){   var promise = Promise.resolve();   inputFiles.files.map( file => promise.then(()=> pFileReader(file)));   promise.then(() => console.log('all done...')); }  function pFileReader(file){   return new Promise((resolve, reject) => {     var fr = new FileReader();       fr.onload = resolve;  // CHANGE to whatever function you want which would eventually call resolve     fr.onerror = reject;     fr.readAsDataURL(file);   }); } 
like image 40
mido Avatar answered Sep 18 '22 11:09

mido