jQuery Deferred and Promises: The Pizza Delivery Story 🍕
Imagine you’re ordering a pizza. You call the pizza shop, and they say: “Your pizza will be ready soon!” But you don’t have to stand at the door waiting. You can watch TV, play games, or do homework. When the pizza arrives, they’ll ring the doorbell!
That’s exactly what Deferred and Promises do in jQuery! They let your code say “I’ll do this later” and keep doing other things until the answer is ready.
🎯 What You’ll Learn
- Deferred Objects – The pizza shop that makes promises
- Promise Method – The delivery tracking slip you get
- Deferred Callbacks – What happens when pizza arrives (or doesn’t!)
- When Method – Ordering multiple pizzas at once
1. Deferred Objects: The Pizza Shop 🏪
A Deferred object is like a pizza shop. It can:
- ✅ Resolve (succeed) – Pizza is ready!
- ❌ Reject (fail) – Sorry, we’re out of cheese!
- ⏳ Notify (update) – Your pizza is in the oven!
Creating a Deferred Object
// Create a new pizza shop (Deferred)
var pizzaShop = $.Deferred();
// Later, when pizza is ready:
pizzaShop.resolve("Pepperoni Pizza");
// Or if something went wrong:
pizzaShop.reject("Oven broke!");
Real Example: Fetching User Data
function getUserData(userId) {
// Create a Deferred
var deferred = $.Deferred();
// Simulate getting data
setTimeout(function() {
if (userId > 0) {
deferred.resolve({
name: "Alex",
age: 25
});
} else {
deferred.reject("Invalid ID!");
}
}, 1000);
// Return the promise
return deferred.promise();
}
🧠 Think of It Like This:
graph TD A["Create Deferred"] --> B{Work Done?} B -->|Success| C["resolve - Pizza Ready!"] B -->|Failure| D["reject - No Pizza Today"] B -->|Update| E["notify - Still Cooking..."]
2. Promise Method: Your Delivery Tracker 📱
When you order pizza, you get a tracking number. You can check the status, but you can’t tell the shop to hurry up or cancel from there.
A Promise is exactly that! It’s a read-only version of the Deferred.
Why Use Promise Instead of Deferred?
| Deferred | Promise |
|---|---|
| Can resolve/reject | Can ONLY watch |
| Full control | Read-only |
| Used inside function | Given to others |
Getting a Promise from Deferred
function loadImage(url) {
var deferred = $.Deferred();
var img = new Image();
img.onload = function() {
deferred.resolve(img);
};
img.onerror = function() {
deferred.reject("Image failed!");
};
img.src = url;
// Give back ONLY the promise
// (not the Deferred itself)
return deferred.promise();
}
// Now use it:
loadImage("cat.jpg")
.done(function(img) {
console.log("Image loaded!");
});
The Magic: Others Can’t Break It!
var deferred = $.Deferred();
var promise = deferred.promise();
// This works (on deferred):
deferred.resolve("Done!");
// This does NOT work (on promise):
// promise.resolve("Hack!"); // ERROR!
Why? Because the promise is like a sealed envelope. You can read what’s inside when it opens, but you can’t change what’s written!
3. Deferred Callbacks: What Happens Next? 🎬
Callbacks are like instructions you give:
- “When pizza arrives, put it on the table”
- “If no pizza, order Chinese food”
- “Either way, set the dinner plates”
The Three Main Callbacks
| Callback | When It Runs | Pizza Example |
|---|---|---|
.done() |
On success | Pizza arrived! |
.fail() |
On failure | No pizza :( |
.always() |
Either way | Set the table |
Example: Handling All Cases
$.ajax({
url: "/api/user"
})
.done(function(data) {
// SUCCESS! 🎉
console.log("Got user:", data);
showUserProfile(data);
})
.fail(function(error) {
// FAILURE! 😢
console.log("Error:", error);
showErrorMessage();
})
.always(function() {
// ALWAYS runs! ⏹️
hideLoadingSpinner();
});
Progress Updates with .progress()
Sometimes you want updates while things happen:
function uploadFile(file) {
var deferred = $.Deferred();
// Simulate upload progress
var progress = 0;
var timer = setInterval(function() {
progress += 10;
deferred.notify(progress);
if (progress >= 100) {
clearInterval(timer);
deferred.resolve("Upload done!");
}
}, 500);
return deferred.promise();
}
// Use it:
uploadFile(myFile)
.progress(function(percent) {
console.log(percent + "% done");
updateProgressBar(percent);
})
.done(function(message) {
console.log(message);
});
graph TD A["Start Task"] --> B["notify - 25%"] B --> C["notify - 50%"] C --> D["notify - 75%"] D --> E{Complete?} E -->|Yes| F["done callback"] E -->|No| G["fail callback"] F --> H["always callback"] G --> H
Chaining Callbacks: The .then() Method
.then() is like saying: “After this, do that”
getUser(123)
.then(function(user) {
// First: get the user
return getOrders(user.id);
})
.then(function(orders) {
// Then: get their orders
return calculateTotal(orders);
})
.then(function(total) {
// Finally: show the total
console.log("Total: quot; + total);
})
.fail(function(error) {
// If ANY step fails
console.log("Something broke!");
});
4. The When Method: Multiple Pizzas! 🍕🍕🍕
What if you’re ordering pizza AND drinks AND dessert from different places? You want to eat when ALL of them arrive!
$.when() waits for multiple promises to complete.
Basic Example
var pizza = orderPizza();
var drinks = orderDrinks();
var dessert = orderDessert();
$.when(pizza, drinks, dessert)
.done(function(p, d, ds) {
// ALL arrived!
console.log("Pizza:", p);
console.log("Drinks:", d);
console.log("Dessert:", ds);
startDinnerParty();
})
.fail(function() {
// At least ONE failed!
console.log("Something missing!");
});
Real Example: Loading Multiple Resources
function loadPage() {
var userData = $.ajax("/api/user");
var postData = $.ajax("/api/posts");
var settings = $.ajax("/api/settings");
$.when(userData, postData, settings)
.done(function(user, posts, config) {
// All 3 loaded successfully!
// user[0], posts[0], config[0]
// contain the data
renderPage(user[0], posts[0], config[0]);
})
.fail(function() {
showError("Failed to load page");
})
.always(function() {
hideLoadingScreen();
});
}
Important: Arguments in $.when()
When using $.when() with AJAX, each argument becomes an array:
$.when(
$.ajax("/api/one"),
$.ajax("/api/two")
).done(function(result1, result2) {
// result1 = [data, status, jqXHR]
// result2 = [data, status, jqXHR]
var data1 = result1[0];
var data2 = result2[0];
});
What If One Fails?
If any promise fails, the whole $.when() fails immediately:
var fast = $.Deferred();
var slow = $.Deferred();
$.when(fast, slow).fail(function() {
console.log("Something failed!");
});
// If fast fails...
fast.reject("Fast broke!");
// ...the whole thing fails immediately
// (doesn't wait for slow)
graph TD A["$.when"] --> B["Promise 1"] A --> C["Promise 2"] A --> D["Promise 3"] B -->|All Success| E[".done runs"] C -->|All Success| E D -->|All Success| E B -->|Any Fail| F[".fail runs"] C -->|Any Fail| F D -->|Any Fail| F E --> G[".always runs"] F --> G
🎓 Quick Summary
| Concept | What It Does | Pizza Analogy |
|---|---|---|
| Deferred | Creates a promise you control | The pizza shop |
| Promise | Read-only tracker | Tracking slip |
| done() | Runs on success | Pizza arrived! |
| fail() | Runs on failure | No pizza :( |
| always() | Runs either way | Set the table |
| progress() | Runs during updates | “In the oven!” |
| then() | Chain multiple steps | Eat, then dessert |
| $.when() | Wait for all | All food arrived! |
🚀 Pro Tips
- Always return promises from functions, not Deferreds
- Use
.then()for chaining instead of nesting callbacks - Handle failures with
.fail()or the second argument of.then() - Use
$.when()when you need multiple async operations to complete
🎯 You Did It!
Now you understand how jQuery handles “I’ll tell you later” situations! Just like waiting for pizza delivery, your code can:
- 📦 Make promises (Deferred)
- 📱 Share tracking info (Promise)
- 🎉 Celebrate when ready (done/fail/always)
- 🍕🍕 Wait for multiple deliveries ($.when)
Go build something awesome! 🚀
