NgRx Effects + Angular HttpClient: Latency behavior when multiple actions trigger concurrent requests
0 reputation · 30 Apr 2025, 08:22 UTC
0 reputation · 30 Apr 2025, 08:22 UTC
Goal: Determine how the interaction between NgRx Effects and Angular's HttpClient influences request‑latency when several Store actions are dispatched concurrently.
Constraints: NgRx Effects process actions synchronously; the choice of mergeMap versus concatMap changes request ordering and concurrency, while the Store runs reducers on the microtask queue and selectors may recompute rapidly. It is unclear which factor dominates latency under realistic load, and whether version‑specific operator internals (pre‑NgRx 12) alter the outcome.
Specific questions:
29275 reputation · 30 Apr 2025, 17:06 UTC
1. mergeMap vs concatMap: mergeMap reduces observed latency only when the browser and server can actually run requests in parallel. Under HTTP/1.1 the ~6-connection limit serializes excess requests anyway, so mergeMap and concatMap often yield similar wall-clock times. Under HTTP/2 with a server that handles concurrent streams, mergeMap lets all N requests fly simultaneously while concatMap forces them into a sequential queue (latency ≈ N × single-request time).
2. Reducer microtask queue: Reducers run synchronously on the microtask queue. Each dispatched action completes its reducer pass before the next microtask runs. With dozens of actions the cumulative reducer time is measurable (typically <0.5 ms per action), but it rarely dominates latency compared to network round-trips.
3. Selector memoization overhead: NgRx createSelector memoizes by reference equality of input slices. During a burst, selectors recompute only when their specific slice changes. Unless you have expensive projections or many distinct slices mutating simultaneously, the overhead is sub-millisecond and not a primary latency driver.
| Confirmed (verifiable in DevTools) | Likely Explanation (depends on environment) |
|---|---|
NgRx Effects default to mergeMap (unlimited inner subscriptions) |
HTTP/2 multiplexing eliminates the 6-connection bottleneck |
| HttpClient creates a cold observable per dispatch — no auto-deduplication | Server-side rate limiting or prioritization caps real concurrency |
| Effect subscription overhead < 1 ms | Reducer microtask batching adds linear but tiny delay |
concatMap serializes inner observables strictly |
Selector recomputation cost scales with slice complexity |
mergeMap → concatMap in the effect; reload and repeat. If latency becomes predictable/sequential, the bottleneck was concurrency contention.What protocol does the target endpoint use — HTTP/1.1 or HTTP/2? If HTTP/1.1, mergeMap gains little over concatMap because the browser connection limit serializes requests anyway. If HTTP/2, mergeMap (or mergeMap with concurrency: N) is the correct choice for latency reduction.
Use comments to ask for clarification. Post a solution as an answer.
29,275 reputation · 30 Apr 2025, 09:53 UTC
When an Effect uses mergeMap, each action immediately triggers a cold HttpClient observable, letting the browser launch requests in parallel up to its per‑domain connection limit (≈6 on most browsers). ConcatMap defers each new request until the previous one completes, so wall‑clock time grows linearly with the number of actions.
Once the limit is reached, additional mergeMap requests are queued by the browser’s networking stack, and the latency curve converges with concatMap. Thus, mergeMap offers a measurable advantage only up to that threshold.
Reducers run synchronously on the microtask queue, but their cumulative ≈0.5 ms per action rarely affects the start time of HTTP calls. Selector memoization adds sub‑millisecond overhead unless many distinct slices mutate simultaneously.
Use mergeMap for bursty action streams when you expect the browser’s connection limit to be the bottleneck; otherwise, the difference is marginal.