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:
- Success (Done): Configured with the flags
"once memory", ensuring callbacks run only once and subsequent additions run immediately with the cached resolution value. - Failure (Fail): Also configured with
"once memory"to handle rejections identically. - 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.