UNPKG

@stnekroman/tstools

Version:

Set of handy tools for TypeScript development

75 lines (61 loc) 2.16 kB
import { LoadingCache } from './LoadingCache'; import { Deffered } from '../Deffered'; import { Throttle } from '../throttle/Throttle'; type DefferedTask<T, ARGS extends unknown[]> = { args: ARGS; deffered: Deffered<T>; }; export abstract class ThrottledCache<T, ARGS extends unknown[] = [string], KEY = string> extends LoadingCache< T, ARGS, KEY > { private readonly queue: DefferedTask<T, ARGS>[] = []; private readonly throttledLoadFn: Throttle.ThrottleFunction; constructor(timeout: number = 200, mapImpl: Map<KEY, Promise<T>> = new Map()) { super(mapImpl); this.throttledLoadFn = Throttle.debounce(() => { this.processQueue(); }, timeout); } public get(...args: ARGS): Promise<T> { if (super.has(...args)) { return super.get(...args); } const defferedTask: DefferedTask<T, ARGS> = { args: args, deffered: new Deffered(), }; this.queue.push(defferedTask); super.put(defferedTask.deffered.promise, ...args); this.throttledLoadFn(); // trigger real loading someday return defferedTask.deffered.promise; } public loadAll(argsArray: ARGS[]): Promise<PromiseSettledResult<T>[]> { return Promise.allSettled(argsArray.map((args: ARGS) => this.load(...args))); // just one by one, override this method if your cache/service knows how to load data in bulk/batch } private processQueue() { const tasks = this.queue.slice(); //extract items this.queue.length = 0; // dont touch queue any more (in this processing frame) if (tasks.length > 0) { this.loadAll(tasks.map((task) => task.args)).then((results: PromiseSettledResult<T>[]) => { for (let i = 0; i < tasks.length; i++) { const result = results[i]; if (result.status === 'fulfilled') { tasks[i].deffered.resolve(result.value); } else { tasks[i].deffered.reject(result.reason); } } }); } } public override clear() { super.clear(); const tasks = this.queue.slice(); this.queue.length = 0; for (const task of tasks) { task.deffered.reject('clear cache'); } } }