[JavaScript] Single Callback For Multiple Asynchronous AJAX Requests (XMLHttpRequest)


Assume that multiple Asynchronous AJAX Requests (XMLHttpRequest) are made, and we would like to have a single final callback function to be run after all the requests are completed successfully. How do we do it? (Reference [1] is actually the same question as the above.)

The following code is my solution to the question:

Source Code (JavaScript)

xhr.js | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
 * Cross-Browser AJAX request (XMLHttpRequest)
 *
 * @param {string} url The url of HTTP GET (AJAX) request.
 * @param {function} callback The callback function if the request succeeds.
 * @param {function} failCallback The callback function if the request fails.
 */
AjaxRequest = function(url, callback, failCallback) {
  var xmlhttp;

  if (window.XMLHttpRequest)
    xmlhttp=new XMLHttpRequest();
  else
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
      if (xmlhttp.status == 200)
        callback(xmlhttp.responseText, url);
      else
        failCallback(url);
    }
  };

  xmlhttp.open("GET", url, true);
  xmlhttp.send();
};

/**
 * Issue Multiple AJAX requests to get data, and a single callback is called
 * after all AJAX requests ar completed successfully.
 *
 * @param {Array} urls The urls of HTTP GET (AJAX) requests.
 * @param {function} callbackMulti The callback function to be run after all
 *                                 AJAX requests are completed successfully.
 *                                 The callbackMulti takes one argument, which
 *                                 is data object of url-responseText pairs.
 * @param {function} failCallbackMulti The callback function to be run if one of
 *                                     the AJAX requests fails.
 */
AjaxRequestsMulti = function(urls, callbackMulti, failCallbackMulti) {
  var isAllCallsCompleted = false;
  var isCallFailed = false;
  var data = {};

  for (var i=0; i<urls.length; i++) {
    var callback = function(responseText, url) {
      if (isCallFailed) return;

      data[url] = responseText;

      // get size of data
      var size = 0;
      for (var index in data) {
        if (data.hasOwnProperty(index))
          size ++;
      }

      if (size == urls.length)
        // all AJAX requests are completed successfully
        callbackMulti(data);
    };

    var failCallback = function(url) {
      isCallFailed = true;
      failCallbackMulti(url);
    };

    AjaxRequest(urls[i], callback, failCallback);
  }
};

There are two main functions in above code snippet. One is AjaxRequest, which is the function to issue single AJAX request (XMLHttpRequest). The other is AjaxRequestsMulti, which is the function to issue multiple AJAX requests. I put a lot of comments in the code in order to trace the code easily.

Usage and Demo

Demo

Source Code for Demo (JavaScript):

usage.js | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * callback function after all AJAX requests ar completed successfully.
 * @param {object} data The JavaScript object which contains url-responseText
 *                      pairs.
 */
callbackMulti = function(data) {
  // write your own callbackMulti here.
  for (var index in data)
    alert(index + ':\n' + data[index]);
};

/**
 * callback function if one of AJAX requests fails.
 * @param {string} url The url of AJAX request that fails.
 */
failCallbackMulti = function(url) {
  // write your own failCallbackMulti here.
  alert(url + ' failed');
};

var urls = ['https://golden-operator-130720.appspot.com/ekadesa.json',
            'https://golden-operator-130720.appspot.com/caturassa.json',
            'https://golden-operator-130720.appspot.com/buddho.json'];

document.getElementById('bt').onclick = function() {
  AjaxRequestsMulti(urls, callbackMulti, failCallbackMulti);
};

The variable urls contains the URLs of AJAX requests, overwrite this variable to fit your needs. The function callbackMulti is the callback function to be run after all AJAX requests are completed successfully, and failCallbackMulti will be run if some requests fail.

Source Code for Demo (HTML):

asynchronous.html | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Single Callback for Multiple Asynchronous XMLHttpRequest Requests</title>
</head>
<body>

<button id="bt" type="button">Click Me to Issue Cross-Domain XHR!</button>

<script src="xhr.js"></script>
<script src="usage.js"></script>
</body>
</html>

Note

If you web page is served via HTTPS, the server that returns data also needs to serve via HTTPS. Otherwise browsers will block the request and make the request fail.


Tested on: Chromium Version 56.0.2924.76 Built on Ubuntu , running on Ubuntu 16.10 (64-bit)


References:

[1]jquery - Javascript callback for multiple ajax calls - Stack Overflow