1

The script I'm writing makes several API calls within a for loop. The problem is that some API calls take longer to load than others so the information is loaded on the page out of order.

For example, I'll make an API call for objects 1-8, but they'll load in the following order: 4, 3, 1, 2, 7, 5, 6, 8

The code is basically the following:

function loadData() {
    for (var i = 0; i < 8; i++) {
        $.getJSON("http://theapi.com/data" + i, function(data) {
            var div = "<div>" + data + "</div>";
            browserElement.innerHTML += div;
        });
    }
}

How can I force the JavaScript not to load the second API call until the first one is finished?

Edit: Using "promises" to chain the API calls results in the script waiting to display the data until ALL of it has been loaded. This is not a desirable result since, if there's enough data, the user may have to wait more than a few seconds to see anything.

Rektroth
  • 23
  • 8
  • Possible duplicate of [async API call inside forEach loop](https://stackoverflow.com/questions/52895277/async-api-call-inside-foreach-loop) – Anurag Srivastava Mar 09 '19 at 16:49
  • Look into [promises](https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Promise). They let you chain requests. – Mouser Mar 09 '19 at 16:49
  • @Mouser - that does not solve this problem - Rektroth is trying to show them in specific order. – Milan Mar 09 '19 at 16:51
  • You can use async..await feature of es7 or you can use a generator to achieve what you're trying to achieve. ref generetor-> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* | async..await -> https://javascript.info/async-await – ishahadathb Mar 09 '19 at 16:55

2 Answers2

3

Create all your divs in the loop and then populate with data once it is available

function loadData() {
    for (var i = 0; i < 8; i++) {
        let div = document.createElement("div");
        browserElement.innerHTML += div;

        $.getJSON("http://theapi.com/data" + i, function(data) {
            div.innerHTML = data;
        });
    }
}
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
Milan
  • 1,903
  • 17
  • 16
  • Alternatively you could Promisify that getJSON call but seems like an overkill for this example :) - the above should do the job. – Milan Mar 09 '19 at 17:13
  • Such a simple solution works so perfectly. Thanks a million. – Rektroth Mar 09 '19 at 17:30
0

$.getJSON returns a Promise, which you can then await to halt execution and get the result:

async function loadData() {
  for (let i = 0; i < 8; i++) {
    const data = await $.getJSON("http://theapi.com/data" + i);
    const div = "<div>" + data + "</div>";
    browserElement.innerHTML += div;
  }
}

To squeeze the whole bandwith out of your connection, you could run the requests in parallel and then show the divs all at once:

async function loadData() {
  const promises = [];
  for (let i = 0; i < 8; i++) {
    promises.push($.getJSON("http://theapi.com/data" + i));

  const result = await Promise.all(promises);

  for(const data of result) {
    const div = "<div>" + data + "</div>";
    browserElement.innerHTML += div;
  }
}

Read on

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • Jonas I like this solution on how to order results of Promises. It would hold 'display' of any of the results until ALL results are obtained though - not sure if that was the intent. – Milan Mar 09 '19 at 17:03
  • @milan not sure either, but that's why I upvoted your answer :) – Jonas Wilms Mar 09 '19 at 17:05
  • Milan has a point. Although it might work, I'm not sure waiting to display the data until ALL of it has been retrieved is desirable. – Rektroth Mar 09 '19 at 17:09
  • 1
    @rektroth well, *it depends on your usecase*. There are some situations were this behaviour is wanted some not. We presented you three different ways to do what you want accurately, choose the way you prefer. off-topic: although your profile is clearly sarcastic, some might feel offended by it, i'd recommend you to either mark it as sarcasm or remove it :) – Jonas Wilms Mar 09 '19 at 17:14
  • @JonasWilms Made the account while in high school and haven't used it in a while. Had absolutely no idea that was there. Thank you for the warning. :) – Rektroth Mar 09 '19 at 17:24