Performance & Memory Leaks
Event Lens tracks event-system overhead in three dimensions: leaks, budgets, and per-subscriber timing.
Finding Memory Leaks
Scenario: Memory keeps growing while the app stays open. Listeners are not being released.
Steps
- Go to the Leaks tab.
- Check the status banner:
- "No memory leaks detected" — all good.
- "Memory leak detected" — open the details.
- Inspect the leak card:
resize listener leakSeverity: HIGHCurrent: 87 listenersThreshold: 50Growth: +25 in 10sStack traces:app.js:142utils.js:89...
- Click a stack trace — the line opens in Sources.
- Cross-check the listener count table:
resize: added 25, removed 2, outstanding 23 <- leakscroll: added 10, removed 10, outstanding 0
Typical cause and fix
// Bad: no removeEventListener
for (let i = 0; i < 100; i++) {
element.addEventListener('resize', handler);
}
// Good: paired with cleanup
function attach() {
element.addEventListener('resize', handler);
}
function detach() {
element.removeEventListener('resize', handler);
}
// Mount
attach();
// Unmount
detach();
Severity levels
- HIGH — listener count exceeds the configured threshold (default 50).
- MEDIUM — unbounded growth over a 10-second window.
- LOW — slight imbalance, may be intentional but worth investigating.
Configuring a Performance Budget
Define hard limits for event behavior. When the limits are crossed, Event Lens flags the offending event with OVER BUDGET.
Steps
- Settings in the header.
- Under Performance Budget:
Max Payload Size: 50 KBMax Frequency: 100 events/secMax Subscriber Duration: 100 msMax Total Per Minute: 10,000 events
- Save.
- Watch for violations in the Budget tab.
Default budget rules
| Rule | Default | Why |
|---|---|---|
| Max payload | 50 KB | Larger payloads slow serialization and bloat memory |
| Max frequency | 100/sec | Higher rates can stutter the UI |
| Max subscriber duration | 100 ms | Long handlers block the event loop |
| Max total/minute | 10,000 | Above this, memory + CPU spike |
Adjust based on what your app actually does. A high-frequency game might raise the frequency budget; a low-traffic dashboard might tighten the payload cap.
Fixing a violation
- Click the violation badge on the event.
- Inspect the payload size and frequency in the detail panel.
- Apply the right fix:
- Payload too large — drop deep clones, remove unused fields, normalize before emitting.
- Too frequent — debounce or throttle the emitter.
- Slow subscriber — make handlers async, simplify computations, defer non-critical work.
- Total/min spike — review whether all events are needed.
Performance Analysis
Scenario: How much do cart:updated subscribers actually cost?
Steps
- Select the event in the list.
- See per-subscriber timings:
Delivery:updateUI() 15mspersistState() 2mstriggerNotification() 89ms <- SLOWTotal: 106ms
- Investigate the slow subscriber:
- Why 89 ms?
- Set a breakpoint or read the code.
- Optimize:
- Shrink the payload.
- Make the handler async (debounce/throttle).
- Simplify the subscriber's logic.
Slow subscriber threshold
Event Lens flags any individual handler that takes > 50 ms with a SLOW badge. The total event delivery time is shown in the detail panel.
A 100 ms total delivery is the rough boundary where users start to feel UI lag — that's also the default subscriber-duration budget.
Tips & Tricks
- Sort by delivery time — find your most expensive events at a glance.
- Combine with Chains — slow subscribers often trigger more slow events; chain view exposes the cascade.
- Watch the Leaks tab during dev — leaks usually appear during heavy interaction (scroll, resize, route changes).
- Set tight budgets early — a 50 ms handler today becomes a 200 ms handler in six months unless someone is watching.
See Also
- Capturing Events — find the events you want to profile.
- Replaying Events — replay a slow event with a stripped-down payload to confirm the cause.
- Network Correlation — slow events often correlate with slow API calls.