Events Benchmarks
Compare event handling and subscription management performance across libraries.
What This Benchmark Measures
This benchmark tests event handling overhead — how much cost each library adds on top of native EventTarget.
Each scenario:
- Creates a recursive chain of
EventTargetlisteners (depth configurable, default 100) - Dispatches 100 events at the root
- Each layer forwards events to its child
EventTarget - Triggers cancellation to tear down all listeners at every level
Fair Comparison: All Libraries Use Native EventTarget
| Library | Event Source | Subscription API | Cleanup |
|---|---|---|---|
| addEventListener | EventTarget |
Native addEventListener |
removeEventListener on abort |
| effection | EventTarget |
on() + each() |
Structured concurrency (halt) |
| rxjs | EventTarget |
fromEvent() |
unsubscribe() via takeUntil |
| effect | EventTarget |
Stream.fromEventListener() |
Fiber interruption (v3) |
| effect-v4 | EventTarget |
Stream.fromEventListener() |
Fiber interruption (v4 beta) |
The addEventListener baseline shows the raw cost of native event handling with manual cleanup. The reactive libraries add abstraction for:
- Automatic cleanup — listeners removed when cancelled
- Subscription tracking — knowing what's active
- Composability — transforming/chaining event streams
The benchmark measures how much overhead each abstraction adds.
Libraries compared: effection, rxjs, effect, effect-v4, addEventListener
Source Code
View the benchmark implementations on GitHub:
Library Comparison
Average latency comparison across all libraries for the selected Effection release.
Percentile Comparison
Memory comparison: see the dedicated Memory Footprint page. The methodology and runtime caveats (V8 hoarding, mimalloc decommit) needed enough explanation that they don't fit on a per-scenario page.
Performance Over Releases
How each library's performance has changed across Effection releases.
Runtime Comparison
Compare performance across runtimes for each library.