How to Use jQuery $.when() for Multiple AJAX Calls
Managing asynchronous JavaScript operations often requires waiting
for several network requests to complete before executing subsequent
logic. jQuery provides the $.when() method, which accepts
multiple Deferred or Promise objects—such as those returned by
$.ajax()—and triggers a callback only when all requests
have resolved. This guide explains how to structure multiple concurrent
AJAX calls using $.when(), process their returned datasets,
handle dynamic lists of requests, and catch potential errors.
The Basic Syntax
Every $.ajax() call returns a jqXHR object,
which implements the Promise interface. By passing these objects as
arguments into $.when(), you can attach a
.done() handler that fires only after every request
completes successfully.
const requestUsers = $.ajax({ url: '/api/users', method: 'GET' });
const requestPosts = $.ajax({ url: '/api/posts', method: 'GET' });
$.when(requestUsers, requestPosts).done(function(usersResult, postsResult) {
// Both requests are finished
console.log('Users Data:', usersResult[0]);
console.log('Posts Data:', postsResult[0]);
});Understanding the Response Arguments
When passing multiple Deferreds to $.when(), the
.done() callback passes an array of three arguments for
each request:
data: The actual payload returned from the server.statusText: A string describing the status (e.g.,"success").jqXHR: The raw jQuery XMLHttpRequest object.
To access the server response directly, read the first element of
each argument (e.g., usersResult[0]). If only a single
Deferred is passed to $.when(), the callback arguments
behave like standard $.ajax().done() arguments rather than
an array.
Handling a Dynamic Number of AJAX Calls
When the number of requests is not known in advance, collect the AJAX
promises into an array and pass them into $.when().
Using the ES6 Spread Operator
In modern JavaScript environments, use the spread operator
(...) to pass the array elements as individual
arguments:
const endpoints = ['/api/users', '/api/posts', '/api/comments'];
const requests = endpoints.map(url => $.ajax({ url: url, method: 'GET' }));
$.when(...requests).done(function(...responses) {
responses.forEach((res, index) => {
console.log(`Response ${index}:`, res[0]);
});
});Using
Function.prototype.apply()
For older environments without ES6 support, use
.apply():
var requests = [
$.ajax({ url: '/api/users' }),
$.ajax({ url: '/api/posts' })
];
$.when.apply($, requests).done(function() {
// Arguments correspond to the requests array
for (var i = 0; i < arguments.length; i++) {
console.log('Data:', arguments[i][0]);
}
});Error Handling with
.fail()
By default, $.when() operates with "fail-fast" behavior.
If any individual AJAX request fails, the entire chain immediately
rejects and invokes the .fail() callback, skipping
.done():
$.when(
$.ajax('/api/valid-endpoint'),
$.ajax('/api/broken-endpoint')
)
.done(function(res1, res2) {
console.log('All requests succeeded');
})
.fail(function(jqXHR, textStatus, errorThrown) {
console.error('At least one request failed:', textStatus, errorThrown);
});If you need all requests to complete regardless of individual success
or failure, handle errors within the individual $.ajax()
definitions using .catch() or standard error callbacks
before passing the promises to $.when().