bitwarden-estensione-browser/src/misc/sequentialize.ts

50 lines
1.8 KiB
TypeScript

/**
* Use as a Decorator on async functions, it will prevent multiple 'active' calls as the same time
*
* If a promise was returned from a previous call to this function, that hasn't yet resolved it will
* be returned, instead of calling the original function again
*
* Results are not cached, once the promise has returned, the next call will result in a fresh call
*
* WARNING: The decorator's scope is singleton, so using it on transient objects can lead to memory leaks.
* Read more at https://github.com/bitwarden/jslib/pull/7
*/
export function sequentialize(cacheKey: (args: any[]) => string) {
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
const originalMethod: () => Promise<any> = descriptor.value;
const caches = new Map<any, Map<string, Promise<any>>>();
const getCache = (obj: any) => {
let cache = caches.get(obj);
if (cache != null) {
return cache;
}
cache = new Map<string, Promise<any>>();
caches.set(obj, cache);
return cache;
};
return {
value: function(...args: any[]) {
const argsCacheKey = cacheKey(args);
const cache = getCache(this);
let response = cache.get(argsCacheKey);
if (response != null) {
return response;
}
response = originalMethod.apply(this, args).then((val: any) => {
cache.delete(argsCacheKey);
return val;
}).catch((err: any) => {
cache.delete(argsCacheKey);
throw err;
});
cache.set(argsCacheKey, response);
return response;
},
};
};
}