rxjs share operator with a timed cache

380 views Asked by At

I'm trying to implement a caching HTTP network call that dumps the result from the cache after a specific amount of time, so I implemented this operator:

export const cacheForMinutes = <T>(minutes?: number) => <T>(source: Observable<T>) => {
    if (!(minutes && minutes > 0))
        return source

    return source.pipe(share<T>({
        connector: () => new ReplaySubject(1),
        resetOnComplete: () => timer(minutes * 60_000)
    }))
}

Then in my service, I use it like this:

getDtoSingle(..., minutesToCache: number) {
    return this.http.get(...).pipe(
        map(...),
        cacheForMinutes(minutesToCache)
    )
}

When I watch the network calls via Chrome developer tools, I can see that it's not actually caching the results for the given time, it's still making the network call each time. What have I done wrong here?

1

There are 1 answers

3
Ahmed Lazhar On

You will need to cache the result in an external variable as you said, and access it with some deep comparison method (like using object-hash) and then remove it when it is done. Example:

import hash from 'object-hash'
const cache: Record<string, Observable<any>> = {}
export function getDtoSingle(query, minutesToCache: number) {
    const q = hash(query)
    return of(0).pipe(swichMap(()=>
      cache[q] ?? (cache[q] = this.http.get(query).pipe(
        finalize(()=>delete cache[q]),
        map(...),
        cacheForMinutes(minutesToCache)
      ))
    ))
}