UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

48 lines (39 loc) 1.73 kB
import type { AnyObject } from '../types.js' import { _getTargetMethodSignature } from './decorator.util.js' /** * Prevents "swarm" of async calls to the same method. * Allows max 1 in-flight promise to exist. * If more calls appear, while Promise is not resolved yet - same Promise is returned. * * Does not support `cacheKey`. * So, the same Promise is returned, regardless of the arguments. */ // eslint-disable-next-line @typescript-eslint/naming-convention export const _SwarmSafe = (): MethodDecorator => (target, key, descriptor) => { if (typeof descriptor.value !== 'function') { throw new TypeError('@_SwarmSafe can be applied only to methods') } const originalFn = descriptor.value const keyStr = String(key) const methodSignature = _getTargetMethodSignature(target, keyStr) const instanceCache = new Map<AnyObject, Promise<any>>() console.log('SwarmSafe constructor called', { key, methodSignature }) // eslint-disable-next-line @typescript-eslint/promise-function-async descriptor.value = function (this: typeof target, ...args: any[]): Promise<any> { console.log('SwarmSafe method called', { key, methodSignature, args }) const ctx = this let inFlightPromise = instanceCache.get(ctx) if (inFlightPromise) { console.log(`SwarmSafe: returning in-flight promise`) return inFlightPromise } console.log(`SwarmSafe: first-time call, creating in-flight promise`) inFlightPromise = originalFn.apply(ctx, args) as Promise<any> instanceCache.set(ctx, inFlightPromise) void inFlightPromise.finally(() => { console.log(`SwarmSafe: in-flight promise resolved`) instanceCache.delete(ctx) }) return inFlightPromise } as any }