ggnoredo
ggnoredo

Reputation: 821

can't figure Javascript loops

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

Upvotes: 0

Views: 53

Answers (3)

Blue
Blue

Reputation: 22911

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();

Upvotes: 2

Titus
Titus

Reputation: 22474

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)

Upvotes: 3

adam
adam

Reputation: 403

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);
    };
}

Upvotes: -1

Related Questions