promise-cache.ts 1.0 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. export class CachePromiseFactory <A, R> {
  2. private readonly running = new Map<string, Promise<R>>()
  3. constructor (
  4. private readonly fn: (arg: A) => Promise<R>,
  5. private readonly keyBuilder: (arg: A) => string
  6. ) {
  7. }
  8. run (arg: A) {
  9. return this.runWithContext(null, arg)
  10. }
  11. runWithContext (ctx: any, arg: A) {
  12. const key = this.keyBuilder(arg)
  13. if (this.running.has(key)) return this.running.get(key)
  14. const p = this.fn.apply(ctx || this, [ arg ])
  15. this.running.set(key, p)
  16. return p.finally(() => this.running.delete(key))
  17. }
  18. }
  19. export function CachePromise (options: {
  20. keyBuilder: (...args: any[]) => string
  21. }) {
  22. return function (_target, _key, descriptor: PropertyDescriptor) {
  23. const promiseCache = new CachePromiseFactory(descriptor.value, options.keyBuilder)
  24. descriptor.value = function () {
  25. if (arguments.length !== 1) throw new Error('Cache promise only support methods with 1 argument')
  26. return promiseCache.runWithContext(this, arguments[0])
  27. }
  28. }
  29. }