Skip to content

perf(benchmark-nanoviews): take the row key and drop record - #218

Merged
dangreen merged 1 commit into
mainfrom
perf/example-benchmark-row-key
Aug 25, 2026
Merged

perf(benchmark-nanoviews): take the row key and drop record#218
dangreen merged 1 commit into
mainfrom
perf/example-benchmark-row-key

Conversation

@dangreen

Copy link
Copy Markdown
Member

The row of the benchmark table needs two things from its item: the id, which is the key it is tracked by, and the label. It was taking both through record:

($row, $index) => {
  const { $id, $label } = record($row)

  return tr({ class: () => $isSelected($id()) ? 'danger' : '' })(
    td({ class: 'col-md-1' })($id),
    

So every row carried a proxy, two child signals, two effects and the links behind them — for one value that never changes and one that is rendered in a single place.

($row, $index, id) => tr({ class: () => $isSelected(id) ? 'danger' : '' })(
  td({ class: 'col-md-1' })(id),
  td({ class: 'col-md-4' })(
    a({ onClick() { $selected(id) } })(
      () => $row().label
    )
  ),
  

The id arrives as the row's key (#217) and the label is read off the row.

Is dropping record for the label safe?

record gives a child computed, so it can hold a text binding still when the row object changes but that field does not. () => $row().label re-runs the binding on any change to the row.

In this app that saving never happens: partialUpdate builds a new object with assignKey for every tenth row only, so the hundred rows that get a new object are exactly the hundred whose label changed. The other nine hundred keep their identity and the reconcile does not write to them at all. The measurement agrees — 03_update10th1k_x16, the one case where the dedup could have paid off, got slightly faster: 3.00 ms → 2.90, CI [−0.30; −0.05].

record still earns its proxy when a row has several fields to write back, or a field that changes far less often than the row it sits in. For one field that is only rendered, it does not.

Measured

Two changes, measured separately, each with 30 iterations per arm and two rounds with the arms alternating.

case before with the key and without record
01 create 1k, script 24.70 20.00 19.50
02 replace all, script 34.95 30.50 30.05
07 create 10k, script 205.05 186.25 181.60
08 append 1k, script 25.15 21.30 21.15
22 run memory 3.449 MB 3.083 2.943

The app bundle goes 12938 B → 11982: with the last consumer gone, the whole record machinery leaves it.

Together with #216 the weighted geometric mean moves 1.139 → 1.103, which puts nanoviews ahead of arrow-js. Computed conservatively: only the measured script deltas are taken off the reference totals, since none of this touches paint and 07's paint swings by ±40 ms between sessions.

The row of the benchmark table needs two things from its item: the id, which is the key it is tracked by, and the label. It was reading both through `record`, so every row carried a proxy, two child signals, two effects and the links behind them - for one value that never changes and one that is read in a single place.

The id now comes from `for_` as the row's key, and the label is read straight off the row. `record` earns its proxy when a row has several fields to write back or a field that changes far less often than the row it sits in; for one field that is only rendered, it does not.

Against the app as it was: `01_run1k` script 24.70 ms -> 19.50, `07_create10k` 205.05 -> 181.60, `22_run-memory` 3.449 MB -> 2.943, and the bundle 12938 B -> 11982 as the whole `record` machinery leaves it.
@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 (34948cd) to head (ac59de3).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #218   +/-   ##
=======================================
  Coverage   85.38%   85.38%           
=======================================
  Files         140      140           
  Lines        3155     3155           
  Branches      594      594           
=======================================
  Hits         2694     2694           
  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 66e9ee3 into main Aug 25, 2026
10 checks passed
@dangreen
dangreen deleted the perf/example-benchmark-row-key branch August 25, 2026 16:14
@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