2

I have the following testAsync function that should return resolved promise after I call resolve().

async function wait(time) {
    await new Promise((resolve, reject) => { setTimeout(resolve, time) });
}

async function testAsync(testParam) {
    return new Promise(async (resolve, reject) => {
        try {
            await wait(2000); // do some async work
            if (testParam === 1) {
                console.log("test param is equal to 1");
                resolve("first IF");
            }
            if (testParam < 10) {
                console.log("test param is smaller than 10");
                resolve("second IF");
            }
        } catch (error) {
            reject(error);
        }
    });
}

(async () => {
    let result = await testAsync(1);
    console.log(result);
})();

console output:

test param is equal to 1
test param is smaller than 10
first IF

My problem is that if I structure the code in a way that includes more calls to resolve() that are not exclusive, the code does resolves the first one it hits but it does not stop and return in that place. Why does it continue? Is resolve() not loosely equal to return? Should I just add return after every resolve() call?

miran80
  • 945
  • 7
  • 22
  • 4
    Calling resolve or reject will not exit the function (return). The rest of the code inside the function will be executed. However, further calls to resolve and reject will be ignored. – mateleco Apr 27 '20 at 11:44
  • [Never pass an `async function` as the executor to `new Promise`](https://stackoverflow.com/q/43036229/1048572)! – Bergi Apr 27 '20 at 13:01
  • I can’t remember where I picked this pattern up but feels good to correct something I was wrong about for months. – miran80 Apr 27 '20 at 13:09

1 Answers1

4

return new Promise(async (resolve, reject) => { is antipattern. Adding async in front of a function will already return a Promise. new Promise has to be only used to convert a none Promise base async function into one that uses a Promise.

Is resolve() not loosely equal to return?

It is only equal in the sense, that it sets the "return" value of the promise, but it does not break the execution flow. So yes you would need to place a return after a resolve if you want to prevent that the following up code is executed.

But as I already said, the shown construct is anyway an anti-pattern and testAsync should look like this:

async function testAsync(testParam) {
  await wait(2000); // do some async work

  if (testParam === 1) {
    console.log("test param is equal to 1");
    return "first IF";
  }

  if (testParam < 10) {
    console.log("test param is smaller than 10");
    return "second IF";
  }
}

And the wait would more likely be written that way:

function wait(time) {
    return new Promise((resolve, reject) => { setTimeout(resolve, time) });
}
t.niese
  • 39,256
  • 9
  • 74
  • 101
  • In my case, 2nd async is needed becuase I have await further down. Without it node throws an error: `SyntaxError: await is only valid in async function` – miran80 Apr 27 '20 at 11:53
  • 1
    @miran80 I added how your shown code should look like. If you already use `await` then using `new Promise` and `resolve`/`reject` does not make sense. – t.niese Apr 27 '20 at 11:55
  • Wow, thank you! I don't know why I never tried this but it looks so much better like that, less boilerplate, less indentation, it is beautiful. – miran80 Apr 27 '20 at 11:56