1

I'm experiencing an unexpected order of execution when using Promises and async/await in JavaScript. Here’s the code snippet:

let a = "Hanzala" let newPromise = new Promise((resolve, reject) => { let error = false if (!error) { setTimeout(() => { console.log("Async Task"); resolve(a) }, 1000) } else { reject("Error") } }); newPromise .then((data) => { console.log("Async resolved",data) return data.toUpperCase() }) .then((data) => { console.log(data+" from second then") }) .catch((e) => { console.log(e + " Async rejected"); }); (async () => { try { const res = await newPromise console.log(res+ " from async await") } catch (error) { console.log(error+"Error form async"); } })(); 

The Output is :

Async Task Async resolved Hanzala Hanzala from async await HANZALA from second then 

Question:

Why does the output order differ from my expectation? Specifically, why does the log "Hanzala from async await" appear before "HANZALA from second then"?

expected Output:

Async Task Async resolved Hanzala HANZALA from second then Hanzala from async await 

Additional Information:

  • I understand that both Promises and async/await use the microtask queue, but I’m unclear on how their execution order is determined in this scenario.
  • Any insights into how the event loop handles this would be appreciated.
3
  • 1
    It's a really good idea to avoid mixing await and .then() chains. Commented Jun 23, 2024 at 15:51
  • This doesn't really have anything to do with async/await. You'd get the same behaviour if you had used newPromise.then(…) instead of await newPromise. Commented Jun 23, 2024 at 17:47
  • "expected Output" - can you explain why exactly you expected that? There is nothing in your code that defines one to happen after the other. Commented Jun 24, 2024 at 10:28

1 Answer 1

5

With const res = await newPromise you only wait for the Promise create by:

let newPromise = new Promise((resolve, reject) => { let error = false if (!error) { setTimeout(() => { console.log("Async Task"); resolve(a) }, 1000) } else { reject("Error") } }); 

because that is the Promise stored in newPromise, and not the Promise returned at the end of the chain from:

.catch((e) => { console.log(e + " Async rejected"); }); 

To get the exact same result you would need to do something like this:

let a = "Hanzala" let newPromise = new Promise((resolve, reject) => { let error = false if (!error) { setTimeout(() => { console.log("Async Task"); resolve(a) }, 1000) } else { reject("Error") } }); let anotherPromise = newPromise .then((data) => { console.log("Async resolved",data) return data.toUpperCase() }) .then((data) => { console.log(data+" from second then") }) .catch((e) => { console.log(e + " Async rejected"); }); (async () => { try { const res = await newPromise; await anotherPromise; console.log(res+ " from async await") } catch (error) { console.log(error+"Error form async"); } })();

This stores the result of the generated Promise in another variable. And you can then wait for both, in the order you would like.

As a note: This way of structuring code is not the best way, first of all in one "unit" (project, module or at least per file basis) you should not mix await/async and then. While storing Promises in variables is not necessarily wrong, you should take care that none of these are orphans.

Sign up to request clarification or add additional context in comments.

2 Comments

But the updated version of your code changes the newPromise variable to be the final value returned by the .then() chain, which does not resolve to the original value of the promise but rather to undefined. This gives output as: Async Task Async resolved Hanzala HANZALA from second then undefined from async await
@HanzalaSarguroh Ah yes I missed that part. It looked like only the ordering is relevant.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.