UNPKG

transitory

Version:

In-memory cache with high hit rates via LFU eviction. Supports time-based expiration, automatic loading and metrics.

62 lines 2.12 kB
import { WrappedCache } from '../WrappedCache'; const DATA = Symbol('loadingData'); /** * Extension to another cache that will load items if they are not cached. */ export class DefaultLoadingCache extends WrappedCache { constructor(options) { super(options.parent, options.removalListener || null); this[DATA] = { promises: new Map(), loader: options.loader || null }; } /** * Get cached value or load it if not currently cached. Updates the usage * of the key. * * @param key - * key to get * @param loader - * optional loader to use for loading the object * @returns * promise that resolves to the loaded value */ get(key, loader) { const currentValue = this.getIfPresent(key); if (currentValue !== null) { return Promise.resolve(currentValue); } const data = this[DATA]; // First check if we are already loading this value let promise = data.promises.get(key); if (promise) return promise; // Create the initial promise if we are not already loading if (typeof loader !== 'undefined') { if (typeof loader !== 'function') { throw new Error('If loader is used it must be a function that returns a value or a Promise'); } promise = Promise.resolve(loader(key)); } else if (data.loader) { promise = Promise.resolve(data.loader(key)); } if (!promise) { throw new Error('No way to load data for key: ' + key); } // Enhance with handler that will remove promise and set value if success const resolve = () => data.promises.delete(key); promise = promise.then(result => { this.set(key, result); resolve(); return result; }).catch(err => { resolve(); throw err; }); data.promises.set(key, promise); return promise; } } //# sourceMappingURL=DefaultLoadingCache.js.map