jQuery Global Selector Performance Implications
Using the jQuery universal selector $('*') retrieves
every single DOM element present on an HTML page, which introduces
severe performance bottlenecks. This article examines the computational
and rendering costs associated with this selector—including massive DOM
traversal overhead, excessive memory allocation, and UI thread
blocking—while providing efficient alternatives to maintain responsive
web applications.
Massive DOM Traversal Overhead
When $('*') executes, jQuery delegates the query to the
native document.querySelectorAll('*') method under modern
browser environments. This forces the browser engine to traverse the
entire DOM tree from top to bottom. In modern web applications where DOM
sizes often exceed thousands of nodes, scanning every element incurs
significant CPU usage. The execution time scales directly with the depth
and complexity of the document tree, making operations noticeably slow
on complex pages.
Excessive Memory Allocation and Garbage Collection
jQuery wraps raw DOM nodes in its own internal object structure to provide utility methods and chaining capabilities. Selecting all elements forces jQuery to instantiate a wrapper containing references to every single node on the page. This causes:
- High Memory Consumption: Creating thousands of jQuery object references rapidly consumes browser heap memory.
- Garbage Collection Pauses: Once the selection goes out of scope, the JavaScript engine's garbage collector must sweep through thousands of dereferenced objects, leading to intermittent frame drops and stuttering ("jank").
UI Thread Blocking and Degradation
JavaScript runs on a single main thread alongside style recalculations, layout rendering, and user input handling. Executing a universal selector blocks this main thread while the query processes and builds the element collection. Consequently:
- User interactions, such as scrolling, clicking, or typing, become unresponsive until the operation completes.
- Animations and transitions stutter or freeze.
- On mobile devices with slower processors and limited memory, this delay can easily cause noticeable freezes lasting hundreds of milliseconds.
Severe Costs of Subsequent Operations
The performance hit worsens significantly when $('*') is
chained with methods that modify styles or read layout metrics:
- Layout Thrashing and Reflows: Chaining visual
modifications (such as
.css(),.addClass(), or.show()) to all elements forces the browser to recalculate styles and re-render the layout across the entire tree. Reading layout properties (such as.width()or.offset()) inside a loop over the universal selection causes continuous reflow thrashing. - Event Listener Overhead: Using
$('*').on('click', ...)binds an independent event listener to every DOM node individually, wasting substantial memory and severely impacting performance.
Efficient Alternatives
To prevent performance degradation, avoid the universal selector entirely and apply targeted DOM querying strategies:
- Target by Class, ID, or Tag: Scope queries to
specific identifiers rather than matching everything (e.g.,
$('.target-class')instead of$('*')). - Context-Restricted Scoping: If a broad search is
genuinely required, restrict the context to an isolated container rather
than the entire document (e.g.,
$('#sub-tree').find('.items')). - Event Delegation: Rather than selecting all child
elements to attach listeners, attach a single listener to a common
ancestor using jQuery event delegation:
$('#container').on('click', '.target-class', function() { // Event handled here }); - CSS-Driven Updates: Apply a single class to a
parent container (such as the
<body>or a primary wrapper) and use CSS descendant rules to adjust child styles, allowing the browser's optimized rendering engine to handle updates rather than JavaScript.