0

I'm trying to solve exactly this problem but in ES2020.

Let's say I have a promise that resolves after one second, and several awaits for that promise, called concurrently from different places. The promise must settle only once, and the awaits should return its result. In the code below, I want all callers to get 1.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

let counter = 0;
async function getSomething() {
  await sleep(1000);
  return ++counter;
}

(async function caller1() {
  console.log(await getSomething());
})();

(async function caller2() {
  console.log(await getSomething());
})();

(async function caller3() {
  console.log(await getSomething());
})();

How can I do that?

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • The issue is that the function `getSomething` is returning a NEW promise every time it is called, so each of your calling functions is awaiting separate ones. You could do something like `const something = getSomething(); (async function caller1() { console.log(await something); })(); (async function caller2() { console.log(await something); })();` and `caller2` will end up evaluating the same Promise as `caller1`. – Derek Jul 02 '20 at 04:36

1 Answers1

0

The simplest pattern is to take advantage of the fact that promises only settle once, and rewrite getSomething like this:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

let counter = 0;
let promise;
async function getSomething() {
  // If another invocation has already initialized the promise, return that promise
  if (promise)
    return promise;
  // Otherwise, we're the first invocation, so initialize the promise...
  promise = sleep(1000).then(() => ++counter);
  // ...and return it
  return promise;
}

(async function caller1() {
  console.log(await getSomething());
})();

(async function caller2() {
  console.log(await getSomething());
})();

(async function caller3() {
  console.log(await getSomething());
})();
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404