Which RxJS operator prevents race conditions without canceling pending HTTP requests?
0 reputation · 01 Nov 2020, 04:51 UTC
0 reputation · 01 Nov 2020, 04:51 UTC
When implementing a search-as-you-type feature in RxJS, switchMap is commonly used to ensure that only the most recent request is processed. This is achieved by unsubscribing from the previous inner observable, which triggers an XHR abort for pending network requests.
However, canceling requests can be problematic for operations where the server must complete the task regardless of whether the client still needs the response, such as updating a user profile or submitting a form. In these scenarios, the goal is to ignore obsolete responses to avoid race conditions while ensuring the server-side process finishes.
What is the recommended operator or pattern to ensure that only the latest emission is handled by the observer without aborting the underlying HTTP request? Does exhaustMap or a combination of mergeMap and filter provide a safer alternative for these non-idempotent operations?
35275 reputation · 01 Nov 2020, 15:31 UTC
The RxJS operator that keeps pending HTTP requests alive while avoiding race conditions is exhaustMap. Unlike switchMap, which unsubscribes from the previous inner observable (causing the XHR or fetch request to abort), exhaustMap ignores new source emissions until the current inner observable completes. This guarantees that the server‑side operation finishes regardless of whether the client still needs the response.
When the source observable emits a value, exhaustMap projects it to an inner observable (e.g., an HTTP call). While that inner observable is in flight, any further source emissions are discarded. Once the inner observable completes, exhaustMap becomes ready to accept a new source value again.
import { exhaustMap } from 'rxjs/operators';
// searchTerm$ is a stream of user input strings
searchTerm$.pipe(
exhaustMap(term => http.get(`/api/search`, { params: { q: term } }))
).subscribe(response => {
// handle the latest completed request only
});
exhaustMap with a timeout or takeUntil to ensure the inner observable eventually completes.exhaustMap drops new emissions while busy, very slow or failed requests may cause the UI to miss user input. Monitor request durations and adjust if necessary.Use comments to ask for clarification. Post a solution as an answer.
6,550 reputation · 01 Nov 2020, 15:09 UTC
While exhaustMap is effective for preventing duplicate submissions, it is important to distinguish it from concatMap when the goal is to ensure every request is processed by the server in the correct order.
To verify which is appropriate for your use case, monitor the browser's Network tab: concatMap will show a series of requests firing one after another as previous ones complete, whereas exhaustMap will show only the first request, with subsequent triggers ignored until the first response returns.