javascriptajaxasynchronouspromise

JavaScript maintain array order after making multiple ajax calls


What I am trying to do is that I have an array with a bunch of integers which represent an id. I loop through the array with the ids. For each id, I make an ajax call which returns to me a JSON and then I append this JSON in my results array. I would like to preserve the order of my results array in the same order I made the ajax calls (ie if I made GET calls to the ids in the order '/url/1', 'url/2', url/3', I would like the results array to store the results from id 1, 2 and 3 in the order the calls were made. Here is the generic code I have to display what I have:

var ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var results = [];
var counter = 1;
ids.forEach(function(id) {
    doAjax('GET', 'url' + id, function(returnValue) {

        

        results.push(returnValue);
        if (counter == 10) {
            //dispatch some event
        }
        
    });



});

The problem is that the order of the results array is different each time because of the asynchronous nature of ajax calls. Is there any way I can ensure that the order of results stays the same after all the ajax calls have been made (i.e. results = [result from id 1, result from id 2, result from id 3,... result from id 10]?


Solution

  • If you use promises, which is a good idea for many reasons, you'll get the results in the order you create them.

    Start by wrapping each AJAX call in a promise and resolve it with the result of the call. Use map() instead of forEach() to propagate an array with all the promises:

    var promises = ids.map(function(id) {
      return new Promise(function(resolve) {
        doAjax('GET', 'url' + id, function(returnValue) {
    
          resolve(returnValue);
        });
      });
    });
    

    Then you can make a single promise that resolves when all the promises in the array have resolved, the callback to this will be passed an array with all the results in the correct order:

    Promise.all(promises).then(function(promiseResults) {
      // The promiseResults array here will contain the results of all AJAX calls in the order you created them
    });
    

    As you can see, you don't need your counter or your declared results variables when using promises.
    This can all be written more neatly and efficiently, but my example will hopefully help you get the idea.