Loop Javascript for (...)

Asked

Viewed 110 times

1

Talk, you guys, blz?

Today I tried to make a Dropzone clone just to test the File and Filereader api. However, I think I’m missing some loop concept.

According to the loop interaction, I take the current file extension to display an image-free Thumb if it is different from (jpg|png|jpeg).

The problem is that the line that checks is always picking up the extension of the last array item

Follows:


for (var i = 0; i < files.length; i++) {
   var fr = new FileReader();
   fr.readAsDataURL(files[i]);
   var name = files[i].name;
   var size = files[i].size / 1000;
   var type = files[i].type;
   var ext = name.substr(name.lastIndexOf("."), name.length);

   fr.onload = function(r) {

     // aqui
     var tag = ext.match(/\.(jpg|jpeg|png)/) ? "img" : "div";

     console.log(tag);

     m += `<div class="up-item hint--bottom" aria-label="deu bom">
              <${tag} src="${r.target.result}" />
           </div>`;
     console.log(m);
   };
}
  • It would not be better to declare in the fr.onload loop before Fs.readAsDataURL?

2 answers

3

This is happening because the function onload does not run immediately, it runs when the file is loaded, and at that point its loop has already run all iterations, so ext is with the value of the last iteration.

Try to send the value of your variables to a separate function, thus the onload can access them safely as the values will not be overwritten during the loop:

for (var i = 0; i < files.length; i++) {
   var fr = new FileReader();
   fr.readAsDataURL(files[i]);
   var name = files[i].name;
   var size = files[i].size / 1000;
   var type = files[i].type;
   var ext = name.substr(name.lastIndexOf("."), name.length);

   onFileLoad(fr, name, size, type, ext)
}

function onFileLoad(fr, name, size, type, ext) {
   fr.onload = function(r) {

     var tag = ext.match(/\.(jpg|jpeg|png)/) ? "img" : "div";

     console.log(tag);

     m += `<div class="up-item hint--bottom" aria-label="deu bom">
              <${tag} src="${r.target.result}" />
           </div>`;
     console.log(m);
   }
}

You can also isolate the value of these variables within the scope of a IIFE

for (var i = 0; i < files.length; i++) {
   var fr = new FileReader();
   fr.readAsDataURL(files[i]);
   var name = files[i].name;
   var size = files[i].size / 1000;
   var type = files[i].type;
   var ext = name.substr(name.lastIndexOf("."), name.length);

   ((fr, name, size, type, ext) => fr.onload = function(r) {

       var tag = ext.match(/\.(jpg|jpeg|png)/) ? "img" : "div";

       console.log(tag);

       m += `<div class="up-item hint--bottom" aria-label="deu bom">
                 <${tag} src="${r.target.result}" />
             </div>`;
       console.log(m);

   })(fr, name, size, type, ext);
}
  • Thanks friend, I understand why :D

3


Not to sound like a copy, I was writing this reply when the other one was published, and that’s what was said. The onload is asynchronous and the for performs all interactions before, returning the last processing.

But I would suggest not using for, but only one recursive function and IIFE (Immediately Invoked Function Expression), function that is executed as soon as it is read.

Just start a control variable with value 0 outside the function, and within the function it will be incremented after each onload up to the limit of items in the array files (files.length). This variable will be the indexes of the array items, as would the variable i of for. Like the onload is asynchronous, just call the same function again when the onload is completed and if the value of the control variable is less than files.length.

Would look like this:

var idx = 0; // inicia a variável de controle
(function arqs(){
   var flen = files.length; // pega o tamanho da array
   if(flen){ // verifica se tem pelo menos 1 item na array
      var fr = new FileReader();
      fr.readAsDataURL(files[idx]);
      var name = files[idx].name;
      var size = files[idx].size / 1000;
      var type = files[idx].type;
      var ext = name.substr(name.lastIndexOf("."), name.length);

      fr.onload = function(r) {

        // aqui
        var tag = ext.match(/\.(jpg|jpeg|png)/) ? "img" : "div";

        console.log(tag);

        m += `<div class="up-item hint--bottom" aria-label="deu bom">
                 <${tag} src="${r.target.result}" />
              </div>`;
        console.log(m);

        idx++; // incrementa a variável

        if(idx < flen) arqs(); // chama a função novamente

      };
   }
})(); // executa a função
  • I could use the while,.

  • 1

    Feel free to post an answer that you like and that is useful and functional.

  • That worked :D hehe

  • @Sam. I suspected asynchronous function, but it went blank, so I came to ask here. I would just like to know if this failure of mine was a lack of knowledge about the scope concepts of Javascript ? Could you tell me? And how did you get your answer? Grateful

Browser other questions tagged

You are not signed in. Login or sign up in order to post.