0
for(var x = 19; x <= 29; x = x + 1) {
  if(x < 29) {
    if(values[x]) {
      var reader = new FileReader();
      var file = $(`#${keys[x]}`)[0].files[0];
      reader.readAsDataURL(file);
      reader.onloadend = function () {
        values[x] = reader.result.slice(reader.result.indexOf(',')+1);
      };
    }
  } else {
     insertAll();
  }
}

the code above only returns the last file and skips all others because it takes time to finish so how do i make sure loop won't continue without finishing reading file

ggnoredo
  • 801
  • 1
  • 13
  • 33
  • 1
    Possible duplicate of [Asynchronous Process inside a javascript for loop](https://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop) – Sergeon Aug 11 '18 at 19:29
  • Note: Usually people just do `++x` instead of the pointlessly long-form `x = x + 1`. – tadman Aug 11 '18 at 19:31

3 Answers3

3

You can use recursion instead of a loop, here is an example:

function recursion(x){
  if(x < 29) {
    if(values[x]) {
      var reader = new FileReader();
      var file = $(`#${keys[x]}`)[0].files[0];
      reader.readAsDataURL(file);
      reader.onloadend = function () {
        values[x] = reader.result.slice(reader.result.indexOf(',')+1);
        recursion(++x)
      };
    }
  } else {
     insertAll();
  }
}
recursion(19)
// You get here only after all the files are read.

The idea is to start reading the next file only after you finish reading the current one (recursion(...) is called inside the reader.onloadend callback)

Titus
  • 22,031
  • 1
  • 23
  • 33
  • This is a good start, but to make it a little more robust it might be worth expanding the number range into an array and pulling off the numbers with `pop` instead of cluttering it up with these magic numbers like `29`. Instead: `recursion([ 19, 20, 21, ... 29 ])` This is a minor difference but allows you to re-order, have holes in the sequence, etc. – tadman Aug 11 '18 at 19:32
  • This recursive approach requires 'extra overhead' linear time as the loading must be processed purely synchronously. That is, there is no option for the run-time to perform parallel IO. – user2864740 Aug 11 '18 at 19:56
  • @user2864740 So is most ways of using promises, like **FrankerZ's** solution for example. That is sequential as well. – Titus Aug 11 '18 at 19:59
  • @Titus I left him a comment too :D – user2864740 Aug 11 '18 at 19:59
2

Recursion can get a little ugly. You should wrap them in promises, and use new es6 await/async syntax:

function readValues(filename) {
  return new Promise((resolve) => {
      const reader = new FileReader();
      const file = $(`#${filename}`)[0].files[0];
      reader.readAsDataURL(file);
      reader.onloadend = function() {
        resolve(reader.result.slice(reader.result.indexOf(',')+1));
      };
  });
}

async function main() {
    let results = {};

    for(let x = 19; x < 29; x++) {
      if(values[x]) {
        results[x] = await readValues(keys[x]);
      }
    }

    insertAll(results);
}

main();

For reading all the files at the same time, I recommend using Promise.all:

function readValues(filename) {
  return new Promise((resolve) => {
      const reader = new FileReader();
      const file = $(`#${filename}`)[0].files[0];
      reader.readAsDataURL(file);
      reader.onloadend = function() {
        resolve(reader.result.slice(reader.result.indexOf(',')+1));
      };
  });
}

async function main() {
  let promises = [];
  let results = {};

  for(let x = 19; x < 29; x++) {
    if(values[x]) {
      const task = readValues(keys[x])
                      // Assign the values in results
                      .then(res => results[x] = res);
      promises.push(task);
    }
  }

  await Promise.all(promises);

  // Results is now an object that you can use.
  insertAll(results);
}

main();
Blue
  • 22,608
  • 7
  • 62
  • 92
-1

create other function to handle read file

for(var x = 19; x <= 29; x = x + 1) {
if(x < 29) {
  if(values[x]) {
    readData(x);
  }
} else {
   insertAll();
}
}

function readData(x){
var reader = new FileReader();
    var file = $(`#${keys[x]}`)[0].files[0];
    reader.readAsDataURL(file);
    reader.onloadend = function () {
      values[x] = reader.result.slice(reader.result.indexOf(',')+1);
    };
}
adam
  • 383
  • 3
  • 7