@stnekroman/tstools
Version:
Set of handy tools for TypeScript development
75 lines (61 loc) • 2.16 kB
text/typescript
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');
}
}
}