How to Create a jQuery Deferred Object

This article provides a straightforward guide on how to create and use a jQuery Deferred object to manage asynchronous operations in JavaScript. You will learn the basic syntax for instantiation, how to manipulate the object's state using resolution and rejection methods, and how to expose a restricted Promise object to ensure safe code execution.

To create a new jQuery Deferred object, call the $.Deferred() factory method:

var deferred = $.Deferred();

Understanding the Lifecycle

A Deferred object starts in a pending state and can transition to one of two final states:

  1. Resolved: Indicates that the asynchronous action succeeded.
  2. Rejected: Indicates that the asynchronous action failed.

Once a Deferred moves to a resolved or rejected state, it remains in that state and cannot change again.

Core Methods

  • deferred.resolve(args): Resolves the Deferred object and calls any doneCallbacks with the supplied arguments.
  • deferred.reject(args): Rejects the Deferred object and calls any failCallbacks with the supplied arguments.
  • deferred.notify(args): Triggers any progressCallbacks to indicate ongoing progress before the object is resolved or rejected.
  • deferred.promise(): Returns the Promise counterpart of the Deferred object. The Promise contains methods to attach callbacks (.done(), .fail(), .then()) but prevents external code from resolving or rejecting the state.

Implementation Example

The most common design pattern is creating a Deferred object inside a function, performing an asynchronous task, and returning its .promise():

function fetchUserData(userId) {
    // 1. Create the Deferred object
    var dfd = $.Deferred();

    // 2. Perform an asynchronous action
    setTimeout(function() {
        if (userId) {
            // Resolve with data on success
            dfd.resolve({ id: userId, name: "Alice" });
        } else {
            // Reject with an error on failure
            dfd.reject("Invalid user ID provided.");
        }
    }, 1000);

    // 3. Return only the promise to protect the deferred state
    return dfd.promise();
}

// Consuming the returned Promise
fetchUserData(42)
    .done(function(user) {
        console.log("User retrieved:", user);
    })
    .fail(function(error) {
        console.error("Error:", error);
    })
    .always(function() {
        console.log("Request completed.");
    });

Passing a Constructor Function

You can also pass an optional function directly into $.Deferred(). The new Deferred instance is passed as both the first argument and the this context to that function:

var dfd = $.Deferred(function(newDeferred) {
    // Automatically called upon creation
    newDeferred.resolve("Completed immediately");
});

dfd.done(function(message) {
    console.log(message);
});