Chaining jQuery AJAX Requests Sequentially
Managing asynchronous operations in JavaScript often requires
executing tasks in a strict order, where each subsequent task depends on
the result of the previous one. This article demonstrates how to chain
multiple jQuery AJAX requests sequentially using jQuery's Promise
implementation. You will learn how to use the .then()
method for static sequences, how to handle dynamic lists of requests
using Array.prototype.reduce(), and how modern
async/await syntax can simplify the process.
Understanding jQuery AJAX Promises
When you call $.ajax(), jQuery returns a
jqXHR object. In jQuery 1.8 and later (especially
modernized in jQuery 3.0+), this object implements the Promise
interface. This allows you to attach callbacks using
.done(), .fail(), and standard Promise methods
like .then().
To run requests sequentially, a .then() callback must
return a new $.ajax() call. This returns a new Promise,
pausing execution of the chain until the new request resolves.
Chaining Fixed Requests with
.then()
The most straightforward way to execute requests sequentially is by
returning the next $.ajax() call inside the
.then() handler of the preceding one.
function runSequentialRequests() {
$.ajax({
url: '/api/step-one',
method: 'GET'
})
.then(function(responseOne) {
console.log('Step 1 complete:', responseOne);
// Return the second AJAX request
return $.ajax({
url: '/api/step-two',
method: 'POST',
data: { stepOneId: responseOne.id }
});
})
.then(function(responseTwo) {
console.log('Step 2 complete:', responseTwo);
// Return the third AJAX request
return $.ajax({
url: '/api/step-three',
method: 'POST',
data: { status: responseTwo.status }
});
})
.then(function(responseThree) {
console.log('All steps completed successfully:', responseThree);
})
.fail(function(error) {
// Catches an error from any request in the chain
console.error('An error occurred during the sequence:', error);
});
}If any request in this chain fails, execution skips remaining
.then() handlers and triggers the .fail()
block immediately.
Chaining
Dynamic Requests with Array.prototype.reduce
When you have an arbitrary number of requests defined in an array,
you can chain them dynamically using
Array.prototype.reduce(). Start with an immediately
resolved Promise using $.when().
const userIds = [101, 102, 103, 104];
function fetchUsersSequentially(ids) {
const results = [];
return ids.reduce(function(previousPromise, currentId) {
return previousPromise.then(function() {
return $.ajax({
url: `/api/users/${currentId}`,
method: 'GET'
}).then(function(userData) {
results.push(userData);
});
});
}, $.when()).then(function() {
return results;
});
}
// Usage
fetchUsersSequentially(userIds)
.done(function(allUsers) {
console.log('Fetched all users in order:', allUsers);
})
.fail(function(err) {
console.error('Sequence stopped due to an error:', err);
});In this pattern, each item in the array waits for the previous Promise to resolve before initiating its own AJAX call.
Modern Alternative:
async and await
In modern JavaScript environments, jQuery's jqXHR
objects are "Thenables," making them directly compatible with native
async/await. This provides the cleanest syntax for
sequential execution.
async function runSequenceModern() {
try {
const stepOne = await $.ajax({ url: '/api/step-one', method: 'GET' });
console.log('Step 1:', stepOne);
const stepTwo = await $.ajax({
url: '/api/step-two',
method: 'POST',
data: { id: stepOne.id }
});
console.log('Step 2:', stepTwo);
const stepThree = await $.ajax({
url: '/api/step-three',
method: 'POST',
data: { status: stepTwo.status }
});
console.log('Final Result:', stepThree);
} catch (error) {
console.error('Sequence failed:', error);
}
}Using await naturally pauses execution until each jQuery
AJAX request settles, avoiding deeply nested callbacks and manual chain
management.