skip to Main Content

the code snippet likes below:

console.log('test')

async function async1() {
    console.log('before wait');
    await wait();
    console.log('after wait');
}

async function wait() {
    try {
        return await new Promise((res, rej) => {
            console.log('wait');
            rej('reject');
        });
    } catch (reason) {
        console.log(reason);
    }
}

async function test() {
    async1();
    console.log('before resolve');
    await Promise.resolve();
    console.log('after resolve');
}

test();

console.log('test end');

you can also run the code in playground

actual result:

[LOG]: "test" 
[LOG]: "before wait" 
[LOG]: "wait" 
[LOG]: "before resolve" 
[LOG]: "test end" 
[LOG]: "reject" 
[LOG]: "after resolve" 
[LOG]: "after wait" 

I thought after wait would be printed first, since it is pushed in the micro task queue early?

where am I wrong?


I took advice from @Seblor

It may become clearer if you replace the async/await with the then function.

then I removed all the async/await

console.log('test')

function async1() {
    console.log('before wait');
    return wait().then(() => {
        console.log('after wait');
    })
}

function wait() {
    return new Promise((res, rej) => {
        console.log('wait');
        rej('reject');
    }).catch((reason) => {
        console.log(reason);
    })
}

function test() {
    async1();
    console.log('before resolve');
    Promise.resolve().then(() => {
        console.log('after resolve');
    })
}

test();

console.log('test end');

Then I realized the first code pushed in micro task queue is the code in catch , followed by console.log('after resolve'), finally console.log('after wait')

2

Answers


  1. In given snippet, it is not waiting for Promise.resolve() to return any response because it is not waiting for any operation. To get rid of this we can simply use chaining of functions like

    async function async3() {
        return new Promise(async(res, rej)=>{
            console.log('before wait async3');
            await wait();
            console.log('after wait async3');
            res()
        })
    }
        
    async function async2() {
        return new Promise(async(res, rej)=>{
            console.log('before wait async2');
            await wait();
            console.log('after wait async2');
            res()
       })
    }
        
    async function async1() {
        return new Promise(async(res, rej)=>{
             console.log('before waitasync1 ');
             await wait();
             console.log('after waitasync1');
             res()
        })
    }
        
    async function wait() {
        try {
            return await new Promise((res, rej) => {
                console.log('wait');
                rej('reject');
            });
        } catch (reason) {
            console.log(reason);
        }
    }
        
    async function test() {
        await async1();
        await async2();
        await async3();
    }
        
    test();
    Login or Signup to reply.
  2. Okay I had a hard time spotting it but I think I get it.

    So we all agree where the issue is, the problem you see is that the promise rejection is executed before the promise that resolves, but the ‘after resolve’ is printed before ‘after wait’.

    The thing is that even though there are 2 promises, there are 3 micro tasks here. The first one is the return await new Promise(, the second one is await Promise.resolve(), and the 3rd one is the awaiting of the call to the function: await wait().

    The call to wait() returns a promise, which you await, creating a new microtask that is queued AFTER await Promise.resolve().

    So the rejecting promise finished, printing ‘reject’, then the resolving promise finished, printing ‘resolve’, and finally the returned promise from wait() is awaited, printing ‘after wait’.

    It may become clearer if you replace the async/await with the then function. So this:

    async function async1() {
        console.log('before wait');
        await wait();
        console.log('after wait');
    }
    

    Would be written like this:

    function async1() {
        console.log('before wait');
        return wait().then(() => {
            console.log('after wait');
        });
    }
    

    So in order of execution (of the micro tasks only):

    1. await new Promise((res, rej) => { registers the 1st Promise
    2. await Promise.resolve() registers the 2nd Promise
    3. The 1st Promise is rejected, printing ‘reject’
    4. Since the 1st promise returns, we can finally register the then callback, creating the 3rd microtask.
    5. The 2nd Promise is resolved, printing ‘after resolve’ since that’s synchronous code
    6. The 3rd micro task is executed, printing ‘after wait’
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search