1

My current <body>...<script>....</script></body> tab has this flow:

<script>

$(document).ready(function(){
    function main(){

        var urlOne = 'https:....';
        var summaryTable = {};
        var distinctKeys = [];
        $.getJSON(urlOne, function(jsonOne) {
            // write code to collect data from urlOne and put it in 'summaryTable' AND 'distinctKeys'
            distinctKeys.append(jsonOne['something']);
        }); // end of first getJSON

        /* ****** the javascript would NOT execute anything below this **** */
        var foo = distinctKeys.length;
        for (var i = 0; i < foo; i++) {

            var curUrl = urlConstant + distinctKeys[i];
            $.getJSON(curUrl, function(jsonTwo) {
                // do stuff to add more info into 'summaryTable'
            }); // end of second getJSON

        }; // end of for loop

    }; // end of main()
    main();
}); // end of all javascript code    
</script>

As I mentioned above, the code wouldn't proceed to execute anything below the /* ****** the javascript would NOT execute anything below this **** */ line. I notice that the distinctKeys and summaryTable are still empty once the first $.getJSON call is executed. I'd like to call getJSON two times in that particular order--the second time is based on the information obtained/collected from the first call. Could anyone explain how I could accomplish that?

Thank you in advanced for your answers!

user1330974
  • 2,500
  • 5
  • 32
  • 60
  • 1
    `the javascript would NOT execute anything below this` why not? do you get an error in the **developer** tools console? - for example, `var urlArray = ['https://one.com', 'https://two.com', 'https://three.com];` has a syntax error – Jaromanda X Sep 25 '17 at 04:01
  • oh, `the second time is based on the information obtained/collected from the first call` but you're not waiting for the first call to even start (let alone finish) before you blindly proceed on to the second and third calls ... AJAX is asynchronous (that's what the first A in AJAX stands for) – Jaromanda X Sep 25 '17 at 04:03
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Teemu Sep 25 '17 at 04:26

2 Answers2

2

Here you go with a solution

var urlArray = ['https://one.com', 'https://two.com', 'https://three.com'];
var i = 0;

var getJSONData = function(){
  $.getJSON(urlArray[i], function(data){
    console.log(data);   

    i++;
    if( i < urlArray.length)
      getJSONData();
  });

};

You have a syntax error var urlArray = ['https://one.com', 'https://two.com', 'https://three.com];, you are missing last single quote.

I would suggest rather than having getJSON method inside a for loop, place it inside a method & call the method once you receive the data from AJAX call and for getting the url's use a variable.

Updated answer based on updated question

$(document).ready(function(){
  function main(){
    var urlOne = 'https:....';
    var summaryTable = {};
    var distinctKeys = [];
    var i = 0;
    $.getJSON(urlOne, function(jsonOne) {
      // write code to collect data from urlOne and put it in 'summaryTable' AND 'distinctKeys'
      distinctKeys.append(jsonOne['something']);
      getJSONData();  // this will be used to call for the first time.
    }); // end of first getJSON

    var getJSONData = function(){
      var curUrl = urlConstant + distinctKeys[i];
      $.getJSON(curUrl, function(data){
        console.log(data);   
        i++;
        if( i < distinctKeys.length)
          getJSONData();
      });
    };

  }; // end of main()
  main();
}); // end of all javascript code    

Hope this will help you.

Shiladitya
  • 12,003
  • 15
  • 25
  • 38
  • I've updated the question. I think what I'm having trouble is how to 1) fill up a couple of variables `summaryTable` and `distinctKeys` using the first `getJSON` call and then 2) use the previous step's info to call the second `getJSON`. But like you said, `getJSON` is async, so how could I possibly get around that issue? Thank you! – user1330974 Sep 25 '17 at 04:14
  • @user1330974 Let me update the answer based on your updated question – Shiladitya Sep 25 '17 at 04:17
  • Thank you! I'm going to bed (it's beyond midnight for me), but I"ll read over your suggested solution and will get back to you in 7-8 hours. :) – user1330974 Sep 25 '17 at 04:19
  • I think I get what you're trying to explain in the updated answer. But when I tried it, the `distinctKeys` is not defined inside the scope of `getJSONData`. How can I make sure `distinctKeys` variable is populated and is defined before calling the second `$.getJSON`? Thank you! – user1330974 Sep 28 '17 at 02:22
  • 1
    @user1330974 I've updated the answer. In your latest scenario your second `AJAX` call should be triggered from 1st `AJAX call success` method, that will make sure your `distinctKeys` variable will have value. – Shiladitya Sep 28 '17 at 03:36
  • Thank you for the follow-up answer. I did something similar to what you suggested and everything works now. – user1330974 Oct 02 '17 at 02:19
  • 1
    @user1330974 Welcome buddy :) – Shiladitya Oct 02 '17 at 04:17
1

Asynchronous functions in Javascript does not block the code execution. It allows the program flow to proceed to next statement without executing what is inside the function block right away. When it has some response, the function inside the asynchronous calls gets executed. Hence the name callback functions.

In your case function(jsonOne) { is a callback function that get's executed after you get the response from server.

A small example to the above statement:

var data = [];
$.getJSON('https://adobe.github.io/Spry/data/json/array-01.js', function(data) {
    console.log("JSON output length is", data.length);
});
console.log("JSON output length is", data.length);

Executing this will log JSON output length is 0 first and then log JSON output length is 5. This explains how Javascript handles Asynchronous calls.

Also be aware that the data variable we are accessing outside callback is different from the data variable we are accessing inside callback. The variable data inside callback can only be accessed inside callback because in Javascript variables have functional scope. Their scope is limited to the function where they are declared.


The next issue is with calling asynchronous functions with for loop. By now, it should be obvious to you that the for loop will finish complete execution even before you get the response for your first getJSON call.

So if you are planning to use value of i inside the response callback, you will always get the terminating value of i for all getJSON response callbacks.

A sample code:

for (var i=0; i<5; i++) {
    $.getJSON('https://adobe.github.io/Spry/data/json/array-01.js', function(jsonData) {
        console.log("Iteration number", i);
    });
}

The output will log Iteration number 5 for all 5 iterations. This is because your for loop finished calling 5 getJSON even before you got response for first getJSON call.

The solution is to take advantage of functional scope of Javascript.

for (var i=0; i<5; i++) {
    (function(x) {
        $.getJSON('https://adobe.github.io/Spry/data/json/array-01.js', function(jsonData) {
            console.log("Iteration number", x);
        });
    )(i);
}

This makes use of immediately invoked anonymous functions in javascript. Basically in your loop, you call a function instead of calling getJSON directly. For this function you pass i as an argument. Inside the function, i is accessible as x. Inside the function the value of i at the time of calling function is retained as x.

For the expert Javascript Ninjas, I prefer anonymous functions because I don't want to pollute global namespace by declaring a function for this non repeating task. I do know efficiency takes a hit but it should be okay for small number of i.

@user1330974: This might not be the direct answer you were expecting but once you understand this concept, you will be able to solve your problem on your own.

  • Thank you for the suggestion. I have updated my question to provide more context. I think I'm having trouble figuring out how to have the second `getJSON` execute under `for` loop. Given the updated code structure, would you have any alternative suggestion to get out of this mess? – user1330974 Sep 25 '17 at 04:11
  • https://stackoverflow.com/questions/37421274/http-request-inside-a-loop –  Sep 25 '17 at 04:12
  • You write a function inside your for loop and pass the value of i inside as an argument. –  Sep 25 '17 at 04:12
  • Thank you! I'll read the link you shared. For now, I need to go to bed (been stuck at this issue for too long and am getting tired...). – user1330974 Sep 25 '17 at 04:16