From c9fc107c07a6cf47bef146e6eea98c4aec15a02c Mon Sep 17 00:00:00 2001 From: Michael Mendy Date: Thu, 4 Sep 2025 16:28:08 -0700 Subject: [PATCH] safer promise handling, uses the passed-in promise if provided, otherwise the global one. --- src/fixtures/FixtureCache.js | 46 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/fixtures/FixtureCache.js b/src/fixtures/FixtureCache.js index 358ff55..087f36b 100644 --- a/src/fixtures/FixtureCache.js +++ b/src/fixtures/FixtureCache.js @@ -1,39 +1,47 @@ -module.exports = function (Promise) { - class FixtureCache { +module.exports = function (P) { + const PromiseCtor = P || Promise; + class FixtureCache { constructor() { - this.cache = {}; - - this.get.bind(this); - this.set.bind(this); - this.setAsync.bind(this); + this.cache = new Map(); + this.inflight = new Map(); } set(key, value) { - this.cache[key] = value; + this.cache.set(key, value); } get(key) { - return this.cache[key]; + return this.cache.get(key); } getOrPromise(key, fn) { - const cacheHit = this.cache[key]; + if (this.cache.has(key)) { + return PromiseCtor.resolve(this.cache.get(key)); + } - if (cacheHit) { - return Promise.resolve(cacheHit); + if (this.inflight.has(key)) { + return this.inflight.get(key); } - return fn().then((result) => { - this.setAsync(key, result); - return result; - }); + const p = PromiseCtor.resolve() + .then(fn) + .then((result) => { + this.setAsync(key, result); + this.inflight.delete(key); + return result; + }) + .catch((err) => { + this.inflight.delete(key); + throw err; + }); + + this.inflight.set(key, p); + return p; } setAsync(key, value) { - setTimeout(() => { - this.set(key, value); - }); + setTimeout(() => this.set(key, value), 0); } }