How jQuery .promise() Works on DOM Elements
The jQuery .promise() method returns a dynamically
generated Promise object that observes an animation or action queue
attached to a collection of DOM elements. This article provides a
comprehensive guide on how .promise() interacts with the
jQuery queue system, its default behavior with the "fx"
animation queue, its syntax and parameters, and practical code examples
demonstrating how to execute code only after all animations on a
selection of elements have completely finished.
Understanding the Queue Mechanism
Every DOM element managed by jQuery can maintain internal queues for
sequential asynchronous operations. The most common of these is the
animation queue, internally identified as "fx". When you
trigger an animation method such as .fadeIn(),
.slideUp(), or .animate(), jQuery places these
operations into the element's "fx" queue.
The .promise() method monitors these queues across every
element in the matched jQuery collection. It constructs a Promise that
remains in a pending state until all actions currently in the specified
queue have finished executing and been dequeued.
Syntax and Arguments
The .promise() method accepts two optional
arguments:
$(selector).promise([type], [target]);type(String): The name of the queue to observe. It defaults to"fx", which is the queue used by standard jQuery animations and visual effects.target(Object): An optional target object. If provided,.promise()attaches the promise methods directly to this object instead of returning a new Promise instance.
How Resolution Works
When .promise() is invoked on a collection of DOM
elements, the following steps occur:
- Queue Inspection: jQuery checks the queue status of every DOM element in the selection.
- Immediate Resolution Check: If the matched elements have no active or pending tasks in the targeted queue, the returned Promise resolves immediately.
- Tracking Completion: If animations are ongoing or queued, the Promise stays pending. It maintains an internal counter of remaining elements with active queues.
- Final Resolution: As each element completes its final queued action, the counter decrements. Once the queue is entirely empty across all elements in the set, the Promise transitions to the resolved state and fires any registered callbacks.
The returned Promise is read-only. It cannot be manually resolved or rejected from outside code; its state is strictly tied to the completion of the queued actions.
Practical Example: Synchronizing Multiple Animations
A frequent challenge in UI development is running code only after
multiple elements finish animating at different times. Callbacks passed
directly to methods like .fadeOut() execute once per
element, creating repetitive or prematurely triggered logic. Using
.promise() ensures execution occurs exactly once after the
entire set finishes.
// Animate three different elements with varying durations
$(".box-1").slideUp(1000);
$(".box-2").fadeOut(2000);
$(".box-3").animate({ width: "50px" }, 1500);
// Wait for all animations across all matching elements to finish
$(".box-1, .box-2, .box-3").promise().done(function() {
console.log("All animations across all selected elements are complete.");
});Because jQuery's Promise object is compatible with the Promises/A+
specification, you can also use modern
Promise.prototype.then() or await inside an
async function:
async function hideModals() {
// Start animations on all alert elements
$(".alert").fadeOut(500);
// Pause execution until all .alert elements finish fading out
await $(".alert").promise();
console.log("All alerts have been removed from view.");
}Observing Custom Queues
While "fx" is the default, .promise() can
monitor custom queues created via the jQuery .queue()
method:
// Add custom tasks to a custom queue named 'taskQueue'
$("#panel").queue("taskQueue", function(next) {
// First operation
next();
});
// Await the completion of the custom queue
$("#panel").promise("taskQueue").done(function() {
console.log("All operations in 'taskQueue' have finished.");
});Summary of Key Behaviors
- Aggregate Tracking: The Promise resolves only when every element in the jQuery collection has cleared its queue.
- Queue Specificity: By default, it exclusively
tracks the
"fx"queue. Non-queue asynchronous operations, such as manualsetTimeoutcalls or standardfetchrequests, are not tracked unless explicitly queued. - Fail-Safe Resolution: If the selected elements do
not exist in the DOM or have no queued animations,
.promise()resolves immediately without throwing errors.