javascriptasync-await

How async function is getting executed before second .then()?


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:


Solution

  • 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.