Skip to content

fix: [#2046] Replace slice(1) with index-based traversal in QuerySelector#2047

Open
TrevorBurnham wants to merge 1 commit intocapricorn86:masterfrom
TrevorBurnham:fix/queryselector-slice-optimization
Open

fix: [#2046] Replace slice(1) with index-based traversal in QuerySelector#2047
TrevorBurnham wants to merge 1 commit intocapricorn86:masterfrom
TrevorBurnham:fix/queryselector-slice-optimization

Conversation

@TrevorBurnham
Copy link
Copy Markdown
Contributor

Fixes #2046

This PR optimizes QuerySelector by replacing inefficient array operations with index-based traversal and accumulator patterns, eliminating unnecessary memory allocations during recursive DOM traversal.

Changes

  1. Adds a selectorIndex parameter to matchSelector, findAll, and findFirst to avoid slice(1) array copies on each recursive call.

  2. Eliminates items.reverse() in matches() by traversing the selector array backwards (from length - 1 to 0) instead of reversing the array first.

  3. Changes findAll from returning arrays (with concat()) to using an accumulator array parameter, eliminating O(n) array copies on each recursive step.

  4. Removes redundant children.indexOf(child) calls in findAll and findFirst by using the existing loop index i.

Before

// In matches():
const reversedItems = items.reverse();  // Mutates array
const result = this.matchSelector(element, reversedItems, 0, ...);

// In findAll - creates new arrays on every recursive call:
matched = matched.concat(
    this.findAll(rootElement, children, selectorItems.slice(1), ...)
);

// Redundant indexOf:
const index = children.indexOf(child);
for (let j = index + 1; ...)

After

// In matches():
const result = this.matchSelector(element, items, items.length - 1, ...);

// In findAll - pushes directly to accumulator:
this.findAll(rootElement, children, selectorItems, nextIndex, ..., matched);

// Uses existing loop index:
for (let j = i + 1; ...)

Impact

  • Eliminates O(n) array copies from slice(1) and concat() on each recursive step
  • Removes array reversal overhead in matches()
  • Removes O(n) indexOf lookups in sibling traversal
  • Reduces GC pressure for complex selectors and deep DOM trees
  • All 143 QuerySelector tests pass

…n QuerySelector

Optimize QuerySelector by replacing array slice operations with index-based
traversal. This eliminates the creation of intermediate arrays on each
recursive call, reducing memory allocations and GC pressure.

Changes:
- matchSelector: Added selectorIndex parameter instead of slicing
- findAll: Added selectorIndex parameter instead of slicing
- findFirst: Added selectorIndex parameter instead of slicing

The selector items array is now passed by reference with an index,
avoiding O(n) array copies on each recursive step.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance: Avoid array slicing during DOM traversal

1 participant