jQuery Deferred & Promises
When code involves tasks that take an unknown amount of time — like AJAX requests, animations, or timers — it becomes necessary to manage what happens after those tasks complete. jQuery's Deferred and Promise objects provide a clean, structured way to handle these asynchronous operations.
What is a Deferred Object?
A Deferred represents a task that has not yet completed. It can be in one of three states:
- Pending: The task is still in progress.
- Resolved: The task completed successfully.
- Rejected: The task failed.
Think of a Deferred like a food order at a restaurant. When placed, the order is pending. When the food arrives, it is resolved. If the kitchen runs out of ingredients, it is rejected.
What is a Promise?
A Promise is a read-only view of a Deferred. It allows other parts of the code to react to the outcome (success or failure) without being able to change the outcome. The Deferred controls the state; the Promise is shared with other code to listen for that state.
Creating a Deferred
var deferred = $.Deferred();
setTimeout(function() {
var success = true;
if (success) {
deferred.resolve("Task completed successfully!");
} else {
deferred.reject("Task failed.");
}
}, 2000);
var promise = deferred.promise();.done() .fail() .always()
.done()— Runs if the Deferred is resolved (success).fail()— Runs if the Deferred is rejected (failure).always()— Runs regardless of success or failure
promise
.done(function(message) {
$("#status").text("SUCCESS: " + message);
})
.fail(function(message) {
$("#status").text("FAILED: " + message);
})
.always(function() {
$("#spinner").hide();
});Complete Working Example
function fetchData() {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve({ name: "Alice", score: 98 });
}, 1500);
return deferred.promise();
}
$(function() {
$("#loadBtn").click(function() {
$("#result").text("Loading...");
fetchData()
.done(function(data) {
$("#result").text(data.name + " scored " + data.score);
})
.fail(function() {
$("#result").text("Failed to load data.");
});
});
});$.when() — Waiting for Multiple Promises
$.when() takes one or more promises and returns a new promise that resolves only when all given promises have resolved. If any one is rejected, the whole thing is rejected.
Example: Wait for Two AJAX Calls
var getUsers = $.getJSON("users.json");
var getProducts = $.getJSON("products.json");
$.when(getUsers, getProducts)
.done(function(usersData, productsData) {
var users = usersData[0];
var products = productsData[0];
console.log("Users: " + users.length + ", Products: " + products.length);
})
.fail(function() {
alert("One or more requests failed.");
});Chaining with .then()
The .then() method accepts success and failure callbacks, and returns a new promise — enabling sequential async chains.
function step1() {
return $.Deferred(function(d) {
setTimeout(function() { d.resolve("Step 1 done"); }, 500);
}).promise();
}
function step2(msg) {
return $.Deferred(function(d) {
setTimeout(function() { d.resolve(msg + " -> Step 2 done"); }, 500);
}).promise();
}
step1()
.then(function(result) {
console.log(result); // "Step 1 done"
return step2(result);
})
.then(function(result) {
console.log(result); // "Step 1 done -> Step 2 done"
});AJAX Requests Already Return Promises
jQuery's AJAX methods already return jqXHR objects that implement the Promise interface.
$.get("profile.json")
.done(function(data) {
$("#name").text(data.name);
})
.fail(function() {
$("#name").text("Could not load profile.");
})
.always(function() {
$("#loadingMsg").hide();
});Key Points
- A Deferred represents an async task; a Promise is the read-only view of that Deferred.
.done()handles success,.fail()handles failure,.always()handles both.$.when()waits for multiple promises to all complete before running a callback..then()chains sequential async operations cleanly.- All jQuery AJAX methods return a jqXHR object that supports the Promise interface.
