Element#matches() compiles the selector on every call
维护者通常 17 天内回复
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 35/100
- Issue 类型
- 重构
- 描述清晰度
- 描述清楚
- 活跃度
- 停滞
- 技术栈
- css, javascript
- 领域
- backend, performance
调研方向
The hot path is esm/shared/matches.js near line 109, where Element#matches() passes the selector string to CSSselect.is(), which recompiles it on every call; prepareMatch already compiles once per call for querySelector* and closest(), so look there for the pattern to reuse. Pull request #349 is already open against this, so check it before starting. Done means a compiled selector is cached per selector string and document kind in a small bounded Map, :scope selectors still compile per call, and the existing matches tests pass with coverage unchanged.
由索引模型根据 Issue 内容生成。
描述
Element#matches(selectors) parses and compiles the selector again on every call. Code that tests many elements against the same few selectors (resolving a <style> sheet over an SVG chart, for example) spends most of its time in css-what's parser and css-select's compiler rather than in matching.
// npm i linkedom && node matches.mjs
import { parseHTML } from 'linkedom';
let svg = '<svg id="chart">';
for (let i = 0; i < 400; i++)
svg += `<g class="node n${i % 7}"><rect class="box"></rect><g class="label"><text class="title"><tspan>${i}</tspan></text></g></g>`;
const { document } = parseHTML(`<!doctype html><html><body>${svg}</svg></body></html>`);
const selectors = [];
for (const a of ['#chart', '#chart .node', '#chart g.label', 'svg'])
for (const b of ['rect', 'text', 'tspan', '.label', '.title', '.box', '.n3', 'g', '.cluster rect', '.edgeLabel', 'g.node', '.missing'])
selectors.push(`${a} ${b}`);
const elements = [...document.querySelectorAll('svg, svg *')];
const t = performance.now();
for (const el of elements)
for (const sel of selectors)
el.matches(sel);
console.log(`${elements.length * selectors.length} calls: ${(performance.now() - t).toFixed(0)} ms`);
Node 22.17.0, macOS, median of runs:
96,048 matches() calls |
|
|---|---|
| linkedom 0.18.13 | ~112 ms |
linkedom main (3fcf145) |
~108 ms |
| same, with the compiled selector kept per selector string | ~20 ms |
A larger run (2,001 elements × 50 selectors, 300k calls), in ms per 100k calls: linkedom 0.18.13 158, main 111, with the compiled selector kept 17; happy-dom 21.0.3 10, jsdom 30.1.3 209.
A CPU profile of main shows css-what parseSelector/unescapeCSS, css-select compileToken/escapeRegex and GC on top; the matching itself is a small share.
Where: esm/shared/matches.js#L109 passes the selector string to CSSselect.is(), which calls compile(query, options) each time (css-select 7.0.0, dist/index.js, is). querySelector* and closest() compile once per call through prepareMatch, so it is matches() that pays per element.
Possible fix: keep the compiled function per selector string and document kind (xmlMode), in a small bounded Map; selectors with :scope keep compiling per call since their context is the element. I have this with a test (coverage unchanged) and can open a PR.
- 主要语言
- HTML
- 星标
- 2.1k
- 派生
- 110
- 平均合并
- 11 天 1 小时
- 30 天内合并 PR
- 1
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
WebReflection/linkedom 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 85/100
WebReflection/linkedom#344 ·
维护者通常 17 天内回复
-
`TextElement.toString()` puts the element text back at the first `><` of the start tag, so an attribute value containing `><` swallows the text of `<style>`, `<script>`, `<title>` and `<textarea>`可能已有人在做 @vsolano9 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 78/100
WebReflection/linkedom#341 ·
维护者通常 17 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
WebReflection/linkedom#340 ·
维护者通常 17 天内回复
-
难度 3/5 半天 新手友好度 50/100
WebReflection/linkedom#345 ·
维护者通常 17 天内回复
-
难度 3/5 1-2 天 新手友好度 68/100
WebReflection/linkedom#342 ·
维护者通常 17 天内回复
查看 WebReflection/linkedom 的全部 Issue
相似的 Issue
-
Filters: ?field:ne=null matches NULL rows instead of non-NULL ones可能已有人在做 @rshdhere 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
Netflix/metaflow-service#504 ·
-
ai-driven-qa bug Minor
难度 2/5 1-3 小时 新手友好度 78/100
linagora/twake-tasks#429 ·
维护者通常 1 天内回复
-
bug domain: database priority: p1 Stellar Wave
难度 2/5 1-3 小时 新手友好度 74/100
StellarState/SS-backend#632 · 1 条评论 ·
维护者通常 1 天内回复
-
bug good first issue
难度 2/5 1-3 小时 新手友好度 78/100
suradet-ps/codeframe#30 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
keyxmakerx/Chronicle#1444 ·
维护者通常 1 天内回复