Last active
January 27, 2022 10:18
-
-
Save Rush/9e7787c79b5947c6fa0c3512970ebd8b to your computer and use it in GitHub Desktop.
Using memoizee with observables
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { decorate } from 'core-decorators'; | |
import * as memoize from 'memoizee'; | |
import { duration, unitOfTime } from 'moment'; | |
import { memoizeObservable } from './rxjs'; | |
type HumanDuration = [number, unitOfTime.DurationConstructor]; | |
export interface MemoizeOptions extends memoize.Options { | |
observable?: boolean; | |
ttl?: HumanDuration; | |
} | |
export function Memoize(options: MemoizeOptions) { | |
const wrapperFunction = options.observable ? | |
memoizeObservable : memoize; | |
if (options.ttl) { | |
options = { | |
...options, | |
maxAge: duration(...options.ttl).asMilliseconds(), | |
}; | |
} | |
return decorate.call(this, wrapperFunction, options); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as memoizee from 'memoizee'; | |
import { pipe, Subject } from 'rxjs'; | |
import { share, takeUntil } from 'rxjs/operators'; | |
type ObservableFunction = <T>(args: any[]) => Observable<T>; | |
export function memoizeObservable(toWrap: ObservableFunction, options: memoizee.Options) { | |
const disposeSymbol = Symbol('___dispose'); | |
const newOptions: memoizee.Options = Object.assign({ | |
normalizer: (args: any[]) => { | |
// not sure why this is needed? without it all arguments yield the same cached value | |
return Array.from(args); | |
}, | |
}, options, { | |
dispose(value: any) { | |
value[disposeSymbol](); | |
}, | |
}); | |
return memoizee(function() { | |
const result$ = toWrap.apply(this, arguments); | |
const expired$ = new Subject(); | |
const sharedResult$ = result$.pipe(takeUntil(expired$), shareReplay(1)); | |
(sharedResult$ as any)[disposeSymbol] = () => expired$.next(); | |
return sharedResult$; | |
}, newOptions); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment