JavaScript Signals Benchmark
Eighteen scenarios, three runtimes, one runner per comparison. Where Quant wins, where it loses, and why each of those is the expected result of how it is built.
Results
- On the project's CI suite (18 scenarios, run 42794143933, 1.1.2): geometric mean 1.03× the time of the better of Reflex and alien-signals, 0.99× Reflex, 0.45× alien-signals. Faster than both on 7 of 18 scenarios, within 25 % of the better one on 17.
- Reorders allocate nothing: with 256 sources rotated every pass, Quant creates and removes no dependency relations, where alien-signals relinks 255.
- Reflex remains faster on reorders and sorts (Quant takes 1.20–1.43× its time there).
The suite is this project's own; lower is better. Node 22.23.4, 9 rounds; each ratio measured within one runner; Reflex bf71877, alien-signals 3.2.1. Earlier snapshots: REPORT.md (Q6), HISTORY.md.
Table view
| Scenario | Quant | Reflex | alien-signals |
|---|---|---|---|
reorder.rotate-256 | 1.00 | 0.83 | 6.67 |
reorder.reverse-8 | 1.00 | 0.83 | 5.88 |
long-reorder.256 | 1.00 | 0.83 | 5.88 |
edit.insert-one-256 | 1.00 | 0.94 | 4.76 |
shared-chaotic.64x32 | 1.00 | 1.28 | 4.55 |
value-sort.256x32 | 1.00 | 0.70 | 3.33 |
fan-in.1024 | 1.00 | 1.01 | 2.63 |
batch.writes-32 | 1.00 | 1.82 | 2.22 |
branch.switch-100 | 1.00 | 1.15 | 2.13 |
stable.wide-256 | 1.00 | 0.85 | 2.13 |
stable.wide-8 | 1.00 | 0.85 | 1.72 |
diamond.8x8 | 1.00 | 1.08 | 1.33 |
replace-half.256 | 1.00 | 1.10 | 1.30 |
fan-out.computeds-1000 | 1.00 | 0.85 | 1.16 |
fan-out.effects-1000 | 1.00 | 1.19 | 1.14 |
static.chain-100 | 1.00 | 0.92 | 1.08 |
lifecycle.mount-100 | 1.00 | 1.52 | 0.96 |
static.read-clean | 1.00 | 0.91 | 0.82 |
| Geometric mean | 1.00 | 1.01 | 2.20 |
Where Quant is ahead
- Batched writes (
batch.writes-32, 0.55 of the better rival). A batch defers watcher delivery only; there is no transaction to open or commit. - Shared dynamic graphs (
shared-chaotic.64x32, 0.78; 0.22 of alien-signals). Reads arrive in a different order every pass, and Quant moves relations where alien-signals relinks them. - Branch switching (
branch.switch-100, 0.87) and replacing half the sources (replace-half.256, 0.91). A relation is allocated only when it is new. - Effect fan-out (
fan-out.effects-1000, 0.88) and diamonds (diamond.8x8, 0.93).
Where it is behind
- Sorting by value (
value-sort.256x32, 1.43 of Reflex) and every reorder scenario (1.20 to 1.21 of Reflex). Reflex's tracking is specialized for permutations. Quant's is general: bounded scans, then one linear walk per pass. That is cheaper to specify and check, and slower on a pure permutation. - The trivial paths:
static.read-clean(1.22 of alien-signals) and the stable wide reads (1.17 of Reflex). A read of a clean value is almost all call overhead, and there is the least to save there. - Computed fan-out (
fan-out.computeds-1000, 1.18 of Reflex).
Against alien-signals alone the reorder scenarios are the widest gap in Quant's favour, at 0.15 to 0.17 of its time. That one is structural, and the counters on the dependency tracking page show it without a clock.
Method
- CI only. Timing runs on GitHub Actions for every build. Local timing is not reported.
- Ratios within one runner. The scenarios run in shards, one job each, and every job times all three runtimes on the same machine. A hosted runner is not a fixed CPU, so times are never compared across jobs; only ratios inside one.
- Fresh process per pair. Every (runtime, scenario) pair runs in its own process each round, in random order, for 9 rounds. A round's value is the median of 21 batches of about 10 ms, after at least 300 ms and 2,000 steps of warm-up.
- Same answers first. Before any timing, the first 64 steps of every scenario must produce the same checksum on all three runtimes. A runtime cannot win by computing something else.
- Fixed rivals. Reflex is a frozen production bundle of commit
bf71877, behind the same minimal host Quant uses; alien-signals is 3.2.1.
What these numbers are not
The suite is this project's own, chosen to cover its task list. It is not a general ranking of signals libraries, and the numbers move between runs: an earlier run had Quant within 25 % of the better rival on all 18 scenarios with a geometric mean of 0.97; the one shown here has 17 of 18 and 1.03. The trajectory over every CI run is in HISTORY.md.
Benchmarks also reward skipped work. A runtime can win a scenario by not doing something its users rely on. Quant's timings count only for a build that passes its differential tests, so speed is measured against fixed semantics. In this project a benchmark may choose between two correct implementations. It may not change what correct means.