I have an Angular 15 application that have a few components which invoking the service method to retrieve some data from the backend. Before the execution the service is checking is there is a required data in the local cache. If there is no data then the service executes the endpoint and store the retrieved data in the cache. In the code it looks so:
export class CryptoMarketService implements MarketService {
private _activeOrdersCache: Cache<Array<Order>> = new Cache<Array<Order>>();
...
getActiveOrders(): Observable<Array<Order>> { // the method should be syncrhonized
if (this._activeOrdersCache.hasCache()) {
return of(this._activeOrdersCache.get());
}
return this.httpClient.get('/market/orders/active')
.pipe(
map((res: any) => {
return Order.fromJsonArray(res);
}),
tap((activeOrders: Array<Order>) => {
this._activeOrdersCache.set(activeOrders, 5, TimeUnit.MINUTES);
})
);
}
But a few components are invoking that method simultaneously so in fact they are both invoking the backend (because the cache can't be initialized in time) and only after getting the response the cache is populating twice. So is there a way to make that service method synchronized (like in java) to make the second thread wait until the first thread is finished, and start the execution the getActiveOrders method only when the cache is settled?
Is the angular have some mechanism like synchronized like in Java or C#?
Don't cache the result, but the observable itself, and share it by using shareReplay()
.
export class CryptoMarketService implements MarketService {
private _activeOrdersCache: Cache<Observable<Array<Order>>> = new Cache<Observable<Array<Order>>>();
getActiveOrders(): Observable<Array<Order>> {
if (!this._activeOrdersCache.hasCache()) {
const obs = this.httpClient.get('/market/orders/active')
.pipe(
...
shareReplay(1)
);
this._activeOrdersCache.set(obs, 5, TimeUnit.MINUTES);
}
return this._activeOrdersCache.get();
}
}
All subscribers will receive the same observable and the result of the stream at that point will be shared, meaning the HTTP call and pipeable operators before shareReplay()
will only run once.