Abhishek
Abhishek

Reputation: 878

Reading multiple files synchronously in Javascript using FileReader

I have a for loop iterating over the number of files

I have to read the first line of each file and add it let's say to a Map having File name as the key and First line of that file as a the value.

I am using FileReader to read the file but it is asynchronous.

When I open a stream to read the file the loop gets incremented before I am done with reading the file and adding my desired entry to the map.

I need a synchronous operation i.e. Read the First line , add it to the Map and then increment the loop and proceed with the next file.

for (var i = 0; i < files.length; i++){

    var file = files[i];

    var reader = new FileReader();

    reader.onload = function(progressEvent){
    var lines = progressEvent.target.result.split('\n');
    firstLine = lines[0];
    alert('FirstLine'+firstLine);   
    //add to Map here 
    }

    reader.readAsText(file);
}

How to modify the code so as to achieve the above mentioned functionality.

Upvotes: 1

Views: 5183

Answers (2)

Ahsan Arshad
Ahsan Arshad

Reputation: 116

I was facing the same issue, what I did was I removed the for loop and used recursive function instead. That way, I was able to handle the sequence of FileReader.

Below I tried to modify your code based on my logic. feel free to ask any question in comments if you need more clarity.

attachmentI = { i: files.length };

function UploadMe() {
   attachmentI.i--;
   if(attachmentI.i > -1){
      var file = files[attachmentI.i];
      var reader = new FileReader();
      reader.onload = function(progressEvent){
         var lines = progressEvent.target.result.split('\n');
         firstLine = lines[0];
         alert('FirstLine'+firstLine);   
         //add to Map here
         UploadMe();
      }
   reader.readAsText(file);
   }

Upvotes: 0

Daniel B
Daniel B

Reputation: 8879

You can use promises and let them run in the order you create them using reduce.

The below code shows how it could be done this way, and you can take a look at this simple JSFiddle that demos the idea.

//create a function that returns a promise
function readFileAndAddToMap(file){
    return new Promise(function(resolve, reject){
        var reader = new FileReader();
        reader.onload = function(progressEvent){
            var lines = progressEvent.target.result.split('\n');
            firstLine = lines[0];
            console.log('FirstLine'+firstLine);   
            //add to Map here 
            resolve();
        }

        reader.onerror = function(error){
            reject(error);
        }

        reader.readAsText(file);
    });
}

//create an array to hold your promises
var promises = [];
for (var i = 0; i < files.length; i++){
    //push to the array
    promises.push(readFileAndAddToMap(files[i]));
}

//use reduce to create a chain in the order of the promise array
promises.reduce(function(cur, next) {
    return cur.then(next);
}, Promise.resolve()).then(function() {
    //all files read and executed!
}).catch(function(error){
    //handle potential error
});

Upvotes: 3

Related Questions