What Is jQuery Deferred Architecture Based On?

The jQuery $.Deferred() architecture is fundamentally based on the CommonJS Promises/A design proposal and is implemented internally using jQuery's specialized $.Callbacks() utility. This design pattern provides a robust way to manage asynchronous workflows by abstracting callback lists into an immutable state machine, separating the control of an operation from its observation.

The CommonJS Promises/A Foundation

At its architectural core, $.Deferred() follows the CommonJS Promises/A design proposal. This specification standardizes how asynchronous operations deliver values or reasons for failure.

Under this model, an asynchronous task operates as a three-state machine:

  • Pending: The default starting state where the operation has neither succeeded nor failed.
  • Resolved (Fulfilled): The operation has completed successfully, triggering completion handlers with the result.
  • Rejected: The operation has failed, triggering failure handlers with an error context.

Once a Deferred object transitions from "pending" to either "resolved" or "rejected," its state becomes immutable. Any callbacks registered after the transition execute immediately with the original payload, eliminating race conditions common to traditional asynchronous event handling.

The Internal Engine: The $.Callbacks() Object

While the behavior follows the Promise pattern, the internal mechanics of jQuery's Deferred object rely directly on $.Callbacks(). The $.Callbacks system is a multi-purpose list-management tool designed to store, manage, and trigger sets of functions.

Internally, an instantiated Deferred object creates three distinct $.Callbacks instances:

  1. Success (Done): Configured with the flags "once memory", ensuring callbacks run only once and subsequent additions run immediately with the cached resolution value.
  2. Failure (Fail): Also configured with "once memory" to handle rejections identically.
  3. Progress: Configured with "memory" to support real-time execution across multiple notifications before final resolution.

State management methods such as resolve(), reject(), and notify() act as triggers that pass context and arguments to their corresponding internal $.Callbacks lists.

Separation of Concerns: Deferred vs. Promise

The architecture enforces a strict boundary between state mutation and state observation by splitting the pattern into two components:

  • The Deferred Object: Represents the producer. It possesses the methods (resolve, reject, resolveWith, rejectWith, notify) necessary to alter state and satisfy the operation.
  • The Promise Object: Represents the consumer. Generated via deferred.promise(), this object exposes only the observation methods (then, done, fail, always, progress).

By returning only the Promise object to calling code, the architecture prevents consumers from inadvertently or maliciously altering the internal state of the asynchronous process, ensuring the task can only be resolved by its creator.