Skip to content

perf(nanoviews): clear a row range with replaceChildren - #216

Merged
dangreen merged 1 commit into
mainfrom
perf/nanoviews-clear-with-replace-children
Aug 25, 2026
Merged

perf(nanoviews): clear a row range with replaceChildren#216
dangreen merged 1 commit into
mainfrom
perf/nanoviews-clear-with-replace-children

Conversation

@dangreen

Copy link
Copy Markdown
Member

Clearing a period walks a Range:

export function removeBetween(start: Node, end: Node): void {
  remove(start.nextSibling!, end.previousSibling!)
}

start and end are the two text markers a period keeps its place with, so what has to go is everything between them. But when those markers stand at the ends of their parent, everything between them is everything the parent holds — and the range is saying the long way what one call says directly.

 export function removeBetween(start: Node, end: Node): void {
-  remove(start.nextSibling!, end.previousSibling!)
+  const parent = start.parentNode!
+
+  if (start === parent.firstChild && end === parent.lastChild) {
+    parent.replaceChildren(start as ChildNode, end as ChildNode)
+  } else {
+    remove(start.nextSibling!, end.previousSibling!)
+  }
 }

An empty range behaves now too: with nothing between the markers, start.nextSibling is end and end.previousSibling is start, so the old path asked for a range that runs backwards.

Measured

09_clear1k_x8, 40 iterations per arm, two rounds with the arms alternating so a drift inside the session cannot pass for an effect:

baseline this branch difference 95% CI
script 34.90 ms 31.65 ms −3.25 [−4.00; −2.40]
total 40.10 ms 36.60 ms −3.50 [−4.10; −2.60]

Both rounds agree. 02_replace1k was measured alongside as a control and did not move (−0.55, CI [−1.60; +0.55]) — removeBetween runs once per period swap there, not on a hot path.

The case profile says why the ceiling is where it is: of 31 ms of JS in 09, Range.deleteContents was 27.98 and the whole reactive teardown of a thousand rows was 2.8. This takes about half of the 6.8 ms gap to vue-vapor; the rest is the difference between replaceChildren and solid's textContent = "" plus that teardown, which stays.

Weighted geometric mean: 1.139 → 1.129.

Cost

+30 B gzip (7558 → 7588). One pin moves: Average usage (Gzip) 3.8 → 3.85 kB. All publics stays under its own.

The same trick does not carry to remove: in the tail of a reconcile the new rows are already in front of the old ones, so the parent holds [start, …new, …old, end] and the range being deleted is far from all of the children.

Lint, tsc --noEmit and 127 tests are green.

`removeBetween` walks a `Range` over everything between the two markers of a period and deletes it. When those markers stand at the ends of their parent, everything between them is everything the parent holds, and the range says the long way what one call says directly.

`parent.replaceChildren(start, end)` sets the parent back to its two markers. In `09_clear1k_x8` the script time falls from 34.90 ms to 31.65 ms and the total from 40.10 to 36.60 - 40 iterations per arm, two rounds with the arms alternating, 95% CI [-4.10; -2.60]. That is about half of the gap to the fastest field in that case, and it moves the weighted geometric mean from 1.139 to 1.129.

The empty range now behaves too: with nothing between the markers the old path asked for a range from `end` to `start`.
@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.38%. Comparing base (85e0ee8) to head (c6d0409).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #216      +/-   ##
==========================================
+ Coverage   85.36%   85.38%   +0.01%     
==========================================
  Files         140      140              
  Lines        3151     3154       +3     
  Branches      593      594       +1     
==========================================
+ Hits         2690     2693       +3     
  Misses        332      332              
  Partials      129      129              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dangreen
dangreen merged commit 5942baf into main Aug 25, 2026
10 checks passed
@dangreen
dangreen deleted the perf/nanoviews-clear-with-replace-children branch August 25, 2026 15:57
@github-actions github-actions Bot mentioned this pull request Aug 25, 2026
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.

1 participant