Element#matches() compiles the selector on every call
Maintainer antworten meist innerhalb von 5 Tagen
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 35/100
- Issue-Typ
- Refactoring
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Veraltet
- Tech-Stack
- css, javascript
- Bereich
- backend, performance
Rechercherichtung
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.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
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.
- Vorherrschende Sprache
- HTML
- Sterne
- 2.1k
- Forks
- 117
- Ø Merge
- 4 T. 13 Std.
- Gemergte PRs (30 T.)
- 2
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus WebReflection/linkedom
-
Parsing splits one text run into several Text nodes at each character reference (`<p>a & b</p>` gives 3 child nodes)Evtl. vergeben @johnhldiver-beep hat das vor 7 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
WebReflection/linkedom#353 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
SVG elements in an HTML document report an upper-cased tagName ("PATH" instead of "path")Evtl. vergeben @jonasporto hat das vor 7 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
WebReflection/linkedom#344 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
`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>`Evtl. vergeben @vsolano9 hat das vor 21 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
WebReflection/linkedom#341 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
WebReflection/linkedom#340 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
In a worker, native functions read through `window` throw "Illegal invocation" (`window.setTimeout`, `window.requestAnimationFrame`)Evtl. vergeben @jonasporto hat das vor 7 Tagen übernommen. Offen
Schwierigkeit 3/5 Ein halber Tag Anfängerfreundlichkeit 50/100
WebReflection/linkedom#345 ·
Maintainer antworten meist innerhalb von 5 Tagen
Alle Issues in WebReflection/linkedom
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
Maintainer antworten meist innerhalb von 1 Tag
-
Area: PDF support
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
orbeon/orbeon-forms#8055 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
JWhite212/SignalLadder#212 ·
Maintainer antworten meist innerhalb von 1 Tag
-
"Claude Code request is missing its initial user message" when the prompt starts with an image pathOffen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
earendil-works/pi-claude-code#31 ·
Maintainer antworten meist innerhalb von 8 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 79/100
Maintainer antworten meist innerhalb von 1 Tag