Boost Front‑End Reliability with Real‑World RxJS Anti‑Corruption Layer Patterns
This article demonstrates how to use RxJS Observable to build robust front‑end anti‑corruption layers, covering stability improvement, splash‑screen timing, automatic fast‑API selection, race‑condition handling, and high‑order data composition with practical code examples and online demos.
After publishing the article "Building Front‑End Anti‑Corruption Strategies with Observable", some readers questioned the simplicity of the examples, suggesting that the same problems could be solved with Promise and that introducing RxJS might increase complexity. While any Observable scenario can theoretically be implemented with Promise, the examples in this article illustrate how an Observable‑based anti‑corruption layer becomes valuable in more complex business situations.
Interface Stability Improvement
Assemble low‑success‑rate APIs into a high‑success‑rate API Online demo: https://stackblitz.com/edit/rxjs-stable-improvement Operators: retry / retryWhen / delay
We simulate an API with a 50% success rate and then use RxJS retry to boost its success probability to 99.9% by retrying up to ten times.
function unstableAPI(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (Math.random() < 0.5) {
resolve(true);
} else {
reject('error');
}
});
}Using retry:
function stabilizedAPI(): Promise<boolean> {
return lastValueFrom(
from(defer(() => unstableAPI())).pipe(retry(10))
);
}To avoid rapid repeated retries that could cause an avalanche effect, we replace retry with retryWhen and add a 1‑second delay between attempts.
function stabilizedAPI(): Promise<boolean> {
return lastValueFrom(
from(defer(() => unstableAPI())).pipe(
retryWhen(errors => errors.pipe(delay(1000), take(10)))
)
);
}Interface Timing Adjustment
Provide a dedicated loading API for the splash screen Online demo: https://stackblitz.com/edit/rxjs-minimal-response-time Operators: forkJoin / delay
The splash screen display time should be the greater of the network delay and a minimal display duration to avoid flicker. The formula is:
Splash display time = Max(networkDelay, minimalDelay)We simulate the network delay with setTimeout:
function initData(): Promise<{ name: string }> {
return new Promise(resolve => {
const networkDelay = Math.random() * 3000;
setTimeout(() => {
resolve({ name: 'lucy' });
}, networkDelay);
});
}Using forkJoin and delay we ensure the splash API respects the minimal delay:
function initDataWithMinimalDelay(minimalDelay: number): Promise<{ name: string }> {
return lastValueFrom(
forkJoin([
from(defer(() => initData())),
of(true).pipe(delay(minimalDelay)),
]).pipe(map(([data]) => data))
);
}Interface Best‑Selection (Racing)
Automatically choose the faster API Online demo: https://stackblitz.com/edit/rxjs-race-query Operator: raceWith
We simulate a fast API (1 s) and a slow API (3 s) and use raceWith to obtain the first response.
function fastAPI(): Promise<string> {
return new Promise(resolve => {
setTimeout(() => resolve('fast data'), 1000);
});
}
function slowAPI(): Promise<string> {
return new Promise(resolve => {
setTimeout(() => resolve('slow data'), 3000);
});
} function getFasterOne(): Promise<string> {
return lastValueFrom(
from(defer(() => fastAPI())).pipe(
raceWith(from(defer(() => slowAPI())))
)
);
}Race‑Condition Handling in the Anti‑Corruption Layer
Observable anti‑corruption layer provides built‑in race handling Online demo: https://stackblitz.com/edit/rxjs-race-condition Operators: exhaustMap / switchMap / concatMap
Using exhaustMap, only the first request is processed while subsequent clicks are ignored:
fromEvent(document.getElementById('button'), 'click')
.pipe(exhaustMap(() => getData()))With switchMap, only the latest request is kept, cancelling previous ones:
fromEvent(document.getElementById('button'), 'click')
.pipe(switchMap(() => getData()))Using concatMap, all requests are queued and executed sequentially:
fromEvent(document.getElementById('button'), 'click')
.pipe(concatMap(() => getData()))High‑Order Data Assembly
Abstract high‑order data requests into a single API Online demo: https://stackblitz.com/edit/rxjs-high-order-query Operators: mergeMap / map / forkJoin
We simulate two APIs: getList returns a list of items, and getStatus returns a status for a given item ID. Using mergeMap and forkJoin, we compose a single observable that returns the list with each item's status attached.
function getList(): Promise<Array<{ name: string; id: string }>> {
return Promise.resolve([
{ name: 'John Brown', id: '1' },
{ name: 'Jim Green', id: '2' }
]);
}
function getStatus(id: string): Promise<string> {
return new Promise(resolve => {
if (id === '2') resolve('old');
else resolve('young');
});
} function getListWithStatus(): Promise<Array<{ name: string; id: string; status: string }>> {
const getList$ = from(defer(() => getList()));
const getStatus$ = (id: string) => from(defer(() => getStatus(id)));
const data$ = getList$.pipe(
mergeMap(list => {
const queries = list.map(item =>
getStatus$(item.id).pipe(map(status => ({ ...item, status })))
);
return forkJoin(queries);
})
);
return lastValueFrom(data$);
}The resulting data looks like:
[
{ "name": "John Brown", "id": "1", "status": "young" },
{ "name": "Jim Green", "id": "2", "status": "old" }
]Conclusion
Observable’s concepts are widely used in reactive programming, and they also bring significant benefits when building front‑end anti‑corruption layers. The article presented several real‑world scenarios where a modest amount of Observable code can replace more verbose Promise‑based implementations. However, for simple cases the added abstraction may be unnecessary; developers should introduce Observable only when the problem complexity justifies it.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
