Understanding Deferred Objects
Grasp the core concepts of jQuery's Deferred objects, how they represent asynchronous operations, and their states (pending, resolved, rejected).
Understanding Deferred Objects is a free jQuery Academy lesson on CoddyKit — lesson 1 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the jQuery Academy learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Async Operations & Callbacks
In web development, many tasks don't happen instantly. Think about fetching data from a server or waiting for a user's click. These are asynchronous operations.
Traditionally, we'd use callbacks: functions that run only after an async task finishes. But nested callbacks can lead to "callback hell," making code hard to read and maintain.
Meet jQuery Deferred
This is where jQuery's Deferred objects come to the rescue! A Deferred object is a powerful way to manage asynchronous operations more cleanly.
It acts like a placeholder for a future result. You attach functions to it that will run when the operation finishes, whether it succeeds or fails, without blocking your main code.
The Three States of Deferred
A Deferred object can be in one of three states, reflecting the status of the asynchronous task it represents:
- Pending: The initial state. The operation hasn't completed yet.
- Resolved: The operation finished successfully.
- Rejected: The operation failed or encountered an error.
Once resolved or rejected, a Deferred object's state cannot change again.
Creating a Deferred Object
You create a new Deferred object using $.Deferred(). This object starts in the pending state.
It provides methods to change its state and to register callback functions that will execute when the state changes.
Try creating one:
var myDeferred = $.Deferred();
console.log('Deferred is pending: ' + (myDeferred.state() === 'pending'));Signalling Success: .resolve()
When your asynchronous operation successfully completes, you call the .resolve() method on your Deferred object.
This changes its state from pending to resolved. Any arguments you pass to .resolve() will be passed to the success callbacks.
Watch the state change:
var myDeferred = $.Deferred();
console.log('Initial state: ' + myDeferred.state());
setTimeout(function() {
myDeferred.resolve('Data fetched!');
console.log('New state: ' + myDeferred.state());
}, 1000);Signalling Failure: .reject()
If your asynchronous operation fails, you call the .reject() method.
This changes the Deferred's state from pending to rejected. Arguments passed to .reject() will be sent to the failure callbacks, often error messages.
See how rejection works:
var myDeferred = $.Deferred();
console.log('Initial state: ' + myDeferred.state());
setTimeout(function() {
myDeferred.reject('Network error!');
console.log('New state: ' + myDeferred.state());
}, 1000);Handling Success with .done()
To react to a successful operation (when the Deferred is resolved), you attach a callback function using the .done() method.
This function will execute only if .resolve() is called, receiving any arguments passed by .resolve().
Let's process some data:
var fetchData = function() {
var dfd = $.Deferred();
setTimeout(function() {
var success = true; // Simulate success
if (success) {
dfd.resolve('User data loaded.');
} else {
dfd.reject('Failed to load user data.');
}
}, 1000);
return dfd;
};
fetchData().done(function(message) {
console.log('Success handler: ' + message);
});Handling Failure with .fail()
Similarly, to handle errors (when the Deferred is rejected), you use the .fail() method.
The callback function passed to .fail() will execute only if .reject() is called, receiving its arguments.
Let's simulate an error:
var fetchData = function() {
var dfd = $.Deferred();
setTimeout(function() {
var success = false; // Simulate failure
if (success) {
dfd.resolve('User data loaded.');
} else {
dfd.reject('Failed to load user data.');
}
}, 1000);
return dfd;
};
fetchData().fail(function(errorMessage) {
console.log('Error handler: ' + errorMessage);
});Always Running: .always()
Sometimes, you have code that needs to run regardless of whether the asynchronous operation succeeded or failed. This is where .always() comes in.
The callback function attached with .always() will execute whether the Deferred is resolved or rejected.
Use .always() for cleanup or final UI updates:
var fetchData = function(shouldSucceed) {
var dfd = $.Deferred();
setTimeout(function() {
if (shouldSucceed) {
dfd.resolve('Data received!');
} else {
dfd.reject('Request failed!');
}
}, 1000);
return dfd;
};
fetchData(false)
.done(function(msg) { console.log('Success: ' + msg); })
.fail(function(err) { console.log('Failure: ' + err); })
.always(function() { console.log('Operation finished.'); });Protecting with .promise()
When you return a Deferred object from a function, you might not want external code to be able to change its state (e.g., call .resolve() or .reject() directly).
The .promise() method returns a "read-only" version of the Deferred object. It only exposes methods for attaching callbacks (like .done(), .fail(), .always()), but not for changing its state.
var createAsyncTask = function() {
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve('Task done!');
}, 500);
// Return only the promise, not the full Deferred object
return dfd.promise();
};
var taskPromise = createAsyncTask();
taskPromise.done(function(msg) {
console.log(msg);
});
// The following would throw an error or do nothing if trying to resolve/reject a promise
// taskPromise.resolve('Attempted to resolve externally'); // This is not possible on a promise objectCheck Your Knowledge
Which of the following methods would you use to register a callback that executes ONLY when a Deferred object successfully completes its asynchronous operation?
Recap: Deferred Foundations
Great job! In this lesson, you've grasped the core concepts of jQuery Deferred objects:
- They manage asynchronous operations, avoiding callback hell.
- They exist in pending, resolved, or rejected states.
- You use
.resolve()for success and.reject()for failure. - Callbacks are attached with
.done()(success),.fail()(failure), and.always()(both). .promise()returns a read-only object to protect state manipulation.
Next, we'll learn how to chain and compose these powerful objects!
Frequently asked questions
Is the “Understanding Deferred Objects” lesson free?
Yes — the full text of “Understanding Deferred Objects” is free to read here on the web, and the jQuery Academy course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the jQuery Academy course, upgrade to CoddyKit PRO.
What will I learn in “Understanding Deferred Objects”?
Grasp the core concepts of jQuery's Deferred objects, how they represent asynchronous operations, and their states (pending, resolved, rejected). You practise jQuery Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start jQuery Academy?
No prior experience is required. jQuery Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Understanding Deferred Objects” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this jQuery Academy lesson?
Yes. Every jQuery Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Understanding Deferred Objects
- Chaining and Composing Promises
- Handling Multiple Asynchronous Tasks