Search code examples
javascriptasync-awaites6-promise

Wait for async function in multiple places


With Promises I can have two separate "threads" both waiting for the same value:

let trigger;
const promise = new Promise(r => {
  console.log('promise is created *once*');
  trigger = value => {
    console.log('trigger is called *once*');
    r(value);
  }
});

(async () => {
  console.log('A waiting');
  const value = await promise;
  console.log(`A finished, got ${value}`);
})();

(async () => {
  console.log('B waiting');
  const value = await promise;
  console.log(`B finished, got ${value}`);
})();

trigger('hello');
console.log('And *two* things are waiting on the single promise');

I've tried to replicate this with async/await but to no avail.

The following snippet does not work:

let trigger = async () => {
  console.log('trigger should be called *once*');
  return 'hello';
};

(async () => {
  console.log('A waiting');
  const value = await trigger; // <-- What do I need to put here?
  console.log(`A finished, got ${value}`);
})();

(async () => {
  console.log('B waiting');
  const value = await trigger; // <-- What do I need to put here?
  console.log(`B finished, got ${value}`);
})();

trigger(); // <-- How can this "kick off" the two awaits above?

Is it possible to write the same functionality in the first snippet, using async/await?

I'm okay with falling back to using Promise if that's needed.


Solution

  • To await, you need to have a reference to the singular promise, so you can't call a function on demand and have that function create a promise and then use that same promise elsewhere (unless the function that creates the promise also holds it in state to return to other callers, like a singleton).

    I'd create a singular promise initially, and then send it to the async functions:

    const trigger = async () => {
      console.log('trigger should be called *once*');
      return 'hello';
    };
    
    async function as1(prom) {
      console.log('A waiting');
      const value = await prom;
      console.log(`A finished, got ${value}`);
    }
    
    async function as2(prom) {
      console.log('B waiting');
      const value = await prom;
      console.log(`B finished, got ${value}`);
    }
    
    const thePromise = trigger();
    as1(thePromise);
    as2(thePromise);

    Don't use async just to return a promise, though - if the purpose of a function is to create a promise, then do it explicitly - that way, it's more clear what your code is meant to do. Async and await have not made the Promise keyword obsolete, it's just syntax sugar which is useful in some situations (and unnecessary in others).