Egli Becerra
Egli Becerra

Reputation: 1040

Ajax API calls in nested loop need to be executed in order

lets say you have a scenario where you needed to create a .csv output in a page's textarea...

So I have 2 arrays which i loop nested within one another. The result of the nested loop is a query that is passed an ajax call... I need to append the result of the ajax call into the textarea.

My question is how do you get the results printed out in the order they are requested (basically the order in the queries array)

//example array to loop.
var outerQuery= ['A', 'B', 'C', 'D', 'E', 'F'];
var outerQueryLegth = outerQuery.length;
var innerQuery= ['1', '2', '3', '4', '5', '6'];
var innerQueryLegth = innerQuery.length;

//the textarea where im going to print the results in order later to open in excel as a .csv file
var $csvText= $('#some-text-area');

//outter loop
$.each(outerQuery, function(outerIndex, outer){
      //Print the row
      $csvText.append('Row' + outer +'\r\n\r\n');
      
      //Nested inner loop (that should execute in order regarless or the time of the api call)
      innerQuery.reduce(function(innerCallback, inner, innerIndex){
        return innerCallback.then(function(){
        	return GoogleAnalyticsAPI(inner).then(function(response){
            $csvText.append(response.column1 +',');
          });
        });//end inner callback
      },Promise.resolve());
});

function GoogleAnalyticsAPI(val) {
	return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({column1: val });
    }, Math.floor((Math.random() * 1000) + 1));
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea id="some-text-area" rows="20" cols="30"></textarea>

As you can see the results in the snippet run pretty out of wack ideally they should print like this:

RowA
1,2,3,4,5,6
RowB
1,2,3,4,5,6
RowC
1,2,3,4,5,6
.
.
.

The innerQuery.reduce i got from Ajax API calls in loop need to be executed in order which really helped thanks @jfriend00

Thanks guys

Upvotes: 1

Views: 722

Answers (2)

jfriend00
jfriend00

Reputation: 707218

You can continue with the same logic you used on the inner .reduce() loop in this prior answer and apply that for the outer loop as well. In addition, you can do this synchronization with plain Javascript concepts.

The key to doing that is that the inner .reduce() loop from the prior answer returns a promise that is only resolved when all the chained async operations in the inner loop are done. You can use that promise to control and synchronize the outer loop like this:

//example array to loop.
var outerQuery= ['A', 'B', 'C', 'D', 'E', 'F'];
var innerQuery= ['1', '2', '3', '4', '5', '6'];

//the textarea where im going to print the results in order later to open in excel as a .csv file
var $csvText= $('#some-text-area');

//outer loop
outerQuery.reduce(function(outerP, outerItem) {
    return outerP.then(function() {
        //Print the row
        $csvText.append('Row' + outerItem +'\r\n');
        return innerQuery.reduce(function(innerP, inner, innerIndex){
            return innerP.then(function(){
                return GoogleAnalyticsAPI(inner).then(function(response){
                $csvText.append(response.column1 +',');
              });
            });
        }, Promise.resolve()).then(function() {
            $csvText.append('\r\n\r\n');
        });      
    });
}, Promise.resolve());

function GoogleAnalyticsAPI(val) {
	return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({column1: val });
    }, Math.floor((Math.random() * 500) + 1));
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea id="some-text-area" rows="20" cols="30"></textarea>

Upvotes: 1

guest271314
guest271314

Reputation: 1

You can use .queue(), .promise() to return functions in sequential order corresponding to index within an array

//example array to loop.
var outerQuery = ['A', 'B', 'C', 'D', 'E', 'F'];
var outerQueryLegth = outerQuery.length;
var innerQuery = ['1', '2', '3', '4', '5', '6'];
var innerQueryLegth = innerQuery.length;
var $csvText = $('#some-text-area');

// create `"outerQuery"` queue
$csvText.queue("outerQuery", $.map(outerQuery, function(outer, index) {
  return function(next) {
    $(this).append((index > 0 ? '\r\n\r\n' : "") 
                    + 'Row' + outer + '\r\n\r\n')
    // create `"innerQuery"` queue
    .queue("innerQueue", $.map(innerQuery, function(inner, innerIndex) {
        return function(_next) {
          return GoogleAnalyticsAPI(inner).then(function(response) {
            $csvText.append(response.column1 + ',');
            // call `_next` function in `"innerQueue"`
          }).then(_next); 
        }
      })).dequeue("innerQueue").promise("innerQueue")
    // call `next` function in `"outerQueue"`
    // when all functions in current `innerIndex`
    // of `innerQueue` array , `"innerQueue"` completes
    .then(next)
  }
})).dequeue("outerQuery");

function GoogleAnalyticsAPI(val) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({
        column1: val
      });
    }, Math.floor((Math.random() * 1000) + 1));
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea id="some-text-area" rows="20" cols="30"></textarea>

Upvotes: 1

Related Questions