Search code examples
javascriptasync-awaites6-promise

How to avoid invoking a promise twice?


I have the following code for simplicity:

const myPromise = new Promise(function(resolve, reject) {
    console.log("Called")
    resolve(10)
});

(async () => {
    console.log(await Promise.race([myPromise]))
    console.log(await Promise.all([myPromise]))
})()

I want to only run myPromise when it's passed into race and all calls. However, I see that it runs immediately, even if I remove the last block of code.

I have modified to defer the invocation by making myPromise be a function that returns a promise, but it's my understanding that I would need to invoke this twice, which would run the code twice.

const myPromise = () => new Promise(function(resolve, reject) {
    console.log("Called")
    resolve(10)
});

(async () => {
    console.log(await Promise.race([myPromise()]))
    console.log(await Promise.all([myPromise()]))
})()

What's the best thing to do here?


Solution

  • You could make a function that caches the Promise in a closure the first time the function is run.

    const makePromise = (() => {
      let prom;
      return () => {
        prom ??= new Promise((resolve, reject) => {
            console.log("Called")
            resolve(10)
        });
        return prom;
      };
    })();
    (async () => {
        console.log(await Promise.race([makePromise()]))
        console.log(await Promise.all([makePromise()]))
    })()

    But if you trust yourself enough for the use of the outer scope to not cause issues, you may as well ditch the IIFE to make things a bit simpler.

    let prom;
    const makePromise = () => {
      prom ??= new Promise((resolve, reject) => {
          console.log("Called")
          resolve(10)
      });
      return prom;
    };
    (async () => {
        console.log(await Promise.race([makePromise()]))
        console.log(await Promise.all([makePromise()]))
    })()