Ordinary local state update
observer result
→ setTick(tick => tick + 1)
→ requestUpdateLane(...)
- Outside a browser event, React assigns ordinary
DefaultLanepriority. - Compatible pending work can coalesce before React commits.
Live, fail-closed experiment
Choose React 18 or React 19. The suite loads exact Apollo and React versions, discards warmups, and runs 96 measured samples in mirrored order. Millisecond values depend on this browser; commit counts and validation checks are the primary result.
The 400-row default gives each React commit substantial real DOM work without adding a synthetic delay.
the matching react-dom/profiling release are imported from esm.sh. Changing React runtime reloads the page so packages from different React releases cannot mix. An unavailable or mismatched package fails the run instead of silently changing the environment.
Ready. The first run downloads exact package versions from esm.sh.
Measured output
The three large values show mean React commits at the largest subscriber count in this run. The table keeps every tested count visible.
Swipe horizontally to see every column →
| Subscribers | Experiment arm | Valid samples | React commits, mean (min–max) | Subscriber renders, mean | Final commit p50 | Final paint p50 |
|---|---|---|---|---|---|---|
| Run the benchmark to populate live results. | ||||||
p50 is the median measured sample. Final paint includes two animation frames and often reflects display cadence; treat it as a completion boundary, not package-only CPU time.
A host task is one browser event-loop turn. A logical notification is one Apollo result publication to one observer. A delivery batch is the group of observer callbacks drained together by the diagnostic arm. p90 is the value at or below which 90% of samples fall.
| Subscribers | Experiment arm | Host tasks | Logical notifications | Delivery batches | Largest batch | Derived layout effects | React CPU mean | Geometry-read mean | Final commit p90 | Final paint p90 |
|---|---|---|---|---|---|---|---|---|---|---|
| Run the benchmark to populate live results. | ||||||||||
Run the benchmark. A result passes only if every required condition holds.
The checks cover exact package versions, identical final data, notification and observer-delivery counts, task and microtask order, no dropped values, and the expected commit progression.
Commit-by-commit illustration
Each box is one measured React commit. A snapshot such as 11110000 means four of eight query consumers show the new value while four still show the old value.
One or more useQuery consumers publish the new Apollo cache value to the UI.
After Q, the fixture's useLayoutEffect reads DOM geometry and updates shared parent state. D models downstream React work; it is not another Apollo result.
Before a run, the strips illustrate the expected eight-subscriber pattern. Run proof replaces them with a measured trace from this browser.
Visible query progression: 00000000 → 11111111
Visible query progression: 00000000 → 10000000 → 11000000 → … → 11111111
Visible query progression: 00000000 → 11111111
| Experiment arm | Commit | Snapshot after render | Derived version | Elapsed ms |
|---|---|---|---|---|
| Run the benchmark to populate the trace. | ||||
Run the benchmark to generate JSON.
Pinned source evidence
Both versions schedule one separate zero-delay browser task per watched ObservableQuery. After each result reaches React, the versions request different update priorities.
observer result
→ setTick(tick => tick + 1)
→ requestUpdateLane(...)
DefaultLane priority.observer result
→ handleStoreChange()
→ forceStoreRerender(..., SyncLane)
External store means state owned outside React—in this case, Apollo's query store.
forceStoreRerender assigns synchronous SyncLane priority.The live timeline verifies separate host tasks, observer callbacks, microtasks, and commits. The lane names are the source-traced explanation for these pinned versions, not a separately manipulated benchmark variable. Apollo PR #11083 introduced the external-store callback to fix update ordering, so restoring the old setter is not a safe fix proposal.
setResultSyncLaneSyncLane