UNPKG

@itwin/core-backend

Version:
106 lines 4.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PromiseMemoizer = exports.QueryablePromise = void 0; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ const core_bentley_1 = require("@itwin/core-bentley"); const BackendLoggerCategory_1 = require("./BackendLoggerCategory"); /** Wrapper around a promise that allows synchronous queries of it's state * @internal */ class QueryablePromise { promise; result; error; _fulfilled = false; _rejected = false; get isPending() { return !this.isFulfilled && !this.isRejected; } get isFulfilled() { return this._fulfilled; } get isRejected() { return this._rejected; } constructor(promise) { this.promise = promise; this.promise.then((res) => { this.result = res; this._fulfilled = true; }).catch((err) => { this.error = err; this._rejected = true; }); } } exports.QueryablePromise = QueryablePromise; /** Utility to cache and retrieve results of long running asynchronous functions. * The cache is keyed on the input arguments passed to these functions * @internal */ class PromiseMemoizer { _cachedPromises = new Map(); _timers = new Map(); _memoizeFn; _generateKeyFn; _maxCacheSize; _cacheTimeout; /** * Constructor * @param memoizeFn Function to memoize * @param generateKeyFn Function to generate the key for the memoized function * @param maxCacheSize Maximum size of the memoizer cache. * If the maximum cache size is exceeded, fulfilled/rejected entries are first discarded - these * may have been unclaimed/orphaned promises. If the cache size is still above the maxCacheSize * threshold, the entire cache is then cleared. */ constructor(memoizeFn, generateKeyFn, maxCacheSize = 500, cacheTimeout = 30000) { this._memoizeFn = memoizeFn; this._generateKeyFn = generateKeyFn; this._maxCacheSize = maxCacheSize; this._cacheTimeout = cacheTimeout; } /** Call the memoized function */ memoize(...args) { const key = this._generateKeyFn(...args); let qp = this._cachedPromises.get(key); if (qp) return qp; if (this._cachedPromises.size >= this._maxCacheSize) { if (this._maxCacheSize > 1) core_bentley_1.Logger.logError(BackendLoggerCategory_1.BackendLoggerCategory.PromiseMemoizer, "Cleared too many unresolved entries in memoizer cache"); this.clearCache(); } const removeCachedPromise = (v) => { const cleanUp = () => { this._cachedPromises.delete(key); this._timers.delete(key); }; this._timers.set(key, setTimeout(cleanUp, this._cacheTimeout)); return v; }; const p = this._memoizeFn(...args).then(removeCachedPromise, (e) => { throw removeCachedPromise(e); // eslint-disable-line @typescript-eslint/only-throw-error }); qp = new QueryablePromise(p); this._cachedPromises.set(key, qp); return qp; } /** Delete the memoized function */ deleteMemoized(...args) { const key = this._generateKeyFn(...args); this._cachedPromises.delete(key); const timer = this._timers.get(key); if (timer) clearTimeout(timer); } /** Clear all entries in the memoizer cache */ clearCache() { this._cachedPromises.clear(); } [Symbol.dispose]() { for (const timer of this._timers.values()) clearTimeout(timer); this._timers.clear(); this.clearCache(); } } exports.PromiseMemoizer = PromiseMemoizer; //# sourceMappingURL=PromiseMemoizer.js.map