3
\$\begingroup\$

There have been multiple discussions on caching http-requests with RXJS. In this question/proposal I want to propose a custom rxjs-operator (non-pure) to provide caching:

const cacheHttp = (cacheKey: string, cacheStorage: any) => (source: Observable<any>) => {
  if (!cacheStorage[cacheKey]) {
    cacheStorage[cacheKey] = source.pipe(
      shareReplay(1)
    );
  }
  return cacheStorage[cacheKey];
};

This operator is not pure, as it modifies one of its arguments (cacheStorage).

This operator could be used like this:

public cachedItems = {};

public getDataForItem$(itemId: string) {
    return this.http.get('/item/' + itemId).pipe(
        cacheHttp(itemId, this.cachedItems),
        shareReplay(1)
    );
}

The client could then call this multiple times without causing superfluous http-requests:

// the following two subscriptions cause http-requests
this.itemService.getDataForItem('firstItem').subscribe((val) => console.log(val));
this.itemService.getDataForItem('secondItem').subscribe((val) => console.log(val));

// all further subscriptions would not cause any additional http-requests
this.itemService.getDataForItem('firstItem').subscribe((val) => console.log(val));
this.itemService.getDataForItem('secondItem').subscribe((val) => console.log(val));
this.itemService.getDataForItem('firstItem').subscribe((val) => console.log(val));
this.itemService.getDataForItem('secondItem').subscribe((val) => console.log(val));

// this subscription would again cause an http-request:
this.itemService.getDataForItem('thirdItem').subscribe((val) => console.log(val));

Is this an acceptable approach to solving the "cache-for-different-requests-problem"? Is there possibly a memory-leak or are there any leaked subscriptions? Is it ok to have side-effects on a provided argument?

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.