fix: [#1882] Fix caching in querySelector and avoid sort #1883
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
hasg=2
).Old Algorithm:
g
selector groups, the algorithm would traverse the DOM to find the first matching element. In the worst case, this traversal could visit alln
nodes. This step is repeated for each group, so the complexity isO(g * n)
.g
matched elements were then sorted to determine the first one in document order. The complexity of this sort isO(g log g)
.The total complexity of the old algorithm was O(g * n + g log g).
New Algorithm:
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 timeO(1)
operation.The total complexity of the new algorithm is O(g * n), making it more efficient for selectors with multiple selector groups.