0

My code:

<script type="text/javascript">
    console.log('First Script');
    var html  = JSON.parse( document.getElementById('json').innerHTML);
    var associatedFiles = html['associatedFiles'];
    if (typeof(associatedFiles) == 'undefined') {
      console.log('No files to compile');
    } else {
      console.log('associatedFiles Found');
      for (i in associatedFiles){           
          $.get(associatedFiles[i], async=false).then(function(data, status){
            $.merge(html.data, data.data);
            console.log('html.data.length:',html.data.length);
          });
      }
      $("#json").html(JSON.stringify(html));   
        console.log('associatedFiles Compiled');
        console.log($("#json").html());
    }   
  </script>

The console shows:

First Script
associatedFiles Found
associatedFiles Compiled
<<$('#json').html() contents>>
html.data.length:903
html.data.length:1354
html.data.length:180

Why are the lines of code after the for loop being executed before the for loop?? I'm fairly new to javascript and jquery so really hoping someone can explain what's going on here. ...

warrentyy
  • 1
  • 1
  • I am not using jquery, but most of the time, this problem happing when some code run async, and i think you need to change the `then` to `complete` – Ofek Jul 18 '21 at 00:49
  • because the stuff in the loop is getting processed by async functions. Those run independently of the synchronous code, and therefore are finishing their task after the sync code has run – Kinglish Jul 18 '21 at 00:49
  • The `for` loop executes completely... then executes then lines below. Long after that (in ms) the callbacks of each triggered `$.get()` requests are executed. – Louys Patrice Bessette Jul 18 '21 at 00:58

1 Answers1

1

Your $.get is asynchronous, meaning that the callback it is passed will only complete when the request completes, and in the meantime subsequent lines are allowed to run. You probably don't want to wait until one associatedFile fetch is completed before the next one begins (since it would be faster for them all to run in parallel rather than in sequence), so your best bet would be to capture each returned promise in a Promise.all and then execute your callbacks and follow-up lines once it completes. Something like:

console.log('First Script');
var html = JSON.parse(document.getElementById('json').innerHTML);
var associatedFiles = html['associatedFiles'];
if (typeof(associatedFiles) == 'undefined') {
  console.log('No files to compile');
} else {
  console.log('associatedFiles Found');
  const fetches = []
  for (i in associatedFiles) {
    // put each fetch in the fetches array;
    const fetch = $.get(associatedFiles[i], async = false);
    fetches.push(fetch);
  }

  Promise.all(fetches).then((dataArr) => { // once all the fetches are complete...
      // iterate over and manage the results...
      for (let data of dataArr) {
        $.merge(html.data, data.data);
        console.log('html.data.length:', html.data.length);
      }

      // then insert your JSON to the DOM
      $("#json").html(JSON.stringify(html));
      console.log('associatedFiles Compiled');
      console.log($("#json").html());
    }

  });

I can't test that, but something like that would probably get you in the right direction. There are other ways to achieve this, so you can look into different ways of handling async in JS for alternatives.

Alexander Nied
  • 12,804
  • 4
  • 25
  • 45
  • Thanks for the explanation! Just tested and this seems to work, and thank you for also explaining why. I'm curious why aysnc=false does not achieve the same effect. – warrentyy Jul 18 '21 at 01:17
  • @warrentyy - I vaguely remember `{ async: false }` but don't totally recall what it was or how it worked. However, in this case: **1)** The [docs for `$.get()`](https://api.jquery.com/jquery.get/) feature no mention of `async`, so I suspect whatever feature that was it was deprecated in more recent versions, and **2)** even if it _were_ supported, I believe it required passing an object where `async` was a property and `false` was a value, but in your code you instead appear to pass a second arg in which `async` is assigned `false`. – Alexander Nied Jul 18 '21 at 02:07