Skip to main content
Version: 0.1.0

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

  1. Go to the Leaks tab.
  2. Check the status banner:
    • "No memory leaks detected" — all good.
    • "Memory leak detected" — open the details.
  3. Inspect the leak card:
    resize listener leak
    Severity: HIGH
    Current: 87 listeners
    Threshold: 50
    Growth: +25 in 10s

    Stack traces:
    app.js:142
    utils.js:89
    ...
  4. Click a stack trace — the line opens in Sources.
  5. Cross-check the listener count table:
    resize: added 25, removed 2, outstanding 23 <- leak
    scroll: 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

  1. Settings in the header.
  2. Under Performance Budget:
    Max Payload Size: 50 KB
    Max Frequency: 100 events/sec
    Max Subscriber Duration: 100 ms
    Max Total Per Minute: 10,000 events
  3. Save.
  4. Watch for violations in the Budget tab.

Default budget rules

RuleDefaultWhy
Max payload50 KBLarger payloads slow serialization and bloat memory
Max frequency100/secHigher rates can stutter the UI
Max subscriber duration100 msLong handlers block the event loop
Max total/minute10,000Above 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

  1. Click the violation badge on the event.
  2. Inspect the payload size and frequency in the detail panel.
  3. 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

  1. Select the event in the list.
  2. See per-subscriber timings:
    Delivery:
    updateUI() 15ms
    persistState() 2ms
    triggerNotification() 89ms <- SLOW
    Total: 106ms
  3. Investigate the slow subscriber:
    • Why 89 ms?
    • Set a breakpoint or read the code.
  4. 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