Skip to content

Conversation

TrevorBurnham
Copy link

Fixes #1882

This pull request optimizes the querySelector method by fixing caching and avoiding an unnecessary sort step.

Caching Bug Fix

The Bug:

The previous implementation of querySelector did not update the cache with the result of the query. It would read from the cache, but it would never write the result back to the cache. This meant that for repeated calls with the same selector, the query would be re-executed every time, negating the benefits of caching.

The Fix:

The new implementation correctly updates the cache with the result of the query. If an element is found, a WeakRef to it is stored in the cache. If no element is found, null is stored.

Cache Invalidation:

happy-dom invalidates the cache for all selectors that were affected by the change. The existing unit test coverage confirms that stale values are not returned from the cache.

Sorting Algorithm Improvement

In this analysis:

  • n is the total number of nodes in the DOM (or the relevant subtree).
  • g is the number of selector groups in the query (e.g., div, p has g=2).

Old Algorithm:

  1. Find Matches: For each of the g selector groups, the algorithm would traverse the DOM to find the first matching element. In the worst case, this traversal could visit all n nodes. This step is repeated for each group, so the complexity is O(g * n).
  2. Sort Matches: The g matched elements were then sorted to determine the first one in document order. The complexity of this sort is O(g log g).

The total complexity of the old algorithm was O(g * n + g log g).

New Algorithm:

  1. Find Matches and Compare: The new algorithm also traverses the DOM for each of the g selector groups. However, instead of collecting all matches and sorting them at the end, it maintains a running "best candidate". When a new match is found, it's compared to the current best, which is a constant time O(1) operation.

The total complexity of the new algorithm is O(g * n), making it more efficient for selectors with multiple selector groups.

This commit fixes a bug where `querySelector` never stored results in its cache. As a result, it was getting a cache miss 100% of the time.

It also replaces an unnecessary sort for results from multiple selector
groups.
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.

querySelector cache always misses
1 participant