2

I am trying to understand asynchronous programming, namely async/await. My current understanding is that using the await keyword will wait for a promise to resolve before continuing on. With this in mind, I made two scripts in Python and Javascript.

Python:

import asyncio


async def stall(func, s):
    await asyncio.sleep(s)
    func()

async def hello():
    def stop():
        print("hello() stop")
    print("hello() start")
    await stall(stop, 5)

async def main():
    def stop():
        print("main() stop")
    print("main() start")
    await asyncio.create_task(hello())
    await asyncio.create_task(stall(stop, 3))

asyncio.run(main())

Javascript:

function stall(func, ms) {
    return new Promise(() => {
        setTimeout(func, ms)
    })
}

async function hello() {
    console.log("hello() start")
    await stall(() => {console.log("hello() stop")}, 5000)
}

async function main() {
    console.log("main() start")
    await hello()
    await stall(() => {console.log("main() stop")}, 3000)
}

main()

When writing the scripts, I thought they would do the same thing. However, the output is different.

Python:

main() start
hello() start
hello() stop
main() stop

Javascript:

main() start
hello() start
hello() stop

Using Powershell, I typed this command:

Measure-Command { node .\async_await.js | out-default }

and this is the output:

main() start
hello() start
hello() stop


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 5
Milliseconds      : 121
Ticks             : 51210409
TotalDays         : 5.9271306712963E-05
TotalHours        : 0.00142251136111111
TotalMinutes      : 0.0853506816666667
TotalSeconds      : 5.1210409
TotalMilliseconds : 5121.0409

Shouldn't it take a total of 8 second? Am I correct in saying that Javascript will wait for hello() but not stall() in the main method? If so, why doesn't Javascript wait for stall() to finish? If not, what is Javascript doing when awaiting the two functions?

Sorry if the answer is obvious or if I made some silly mistake.

1
  • 2
    setTimeout doesn't know anything about async coding. It is very, very different from asyncio.sleep. Thus, it returns immediately, so your stall doesn't really stall. The program ends before the second timeout expires. Commented Dec 11, 2022 at 5:56

1 Answer 1

1

The promise you're returning from stall never settles (it is never fulfilled or rejected) which ends up suspending your hello() function indefinitely at its first await. To fulfil a promise that you create using new Promise(), you need to call resolve() within its executor function. You can do this by updating the executor to use the resolveFunc it gets passed and then call that when the setTimeout() callback is called:

function stall(func, ms) {
  return new Promise((resolve) => { // use the resolveFunc
    setTimeout(() => {
      resolve(); // resolve the promise
      func();
    }, ms);
  });
}

async function hello() {
  console.log("hello() start");
  await stall(() => {console.log("hello() stop")}, 5000);
}

async function main() {
  console.log("main() start");
  await hello();
  await stall(() => {console.log("main() stop")}, 3000);
}

main();

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

5 Comments

Thanks. I'm a little confused, if you could provide some clarification. hello() gets suspended indefinitely, but stops waiting after 5 seconds? What's the difference between suspending hello() indefinitely and suspending main() indefinitely? If I made stall() async instead of explicitly returning a new Promise, how would I resolve the Promise correctly?
@asdf When a function hits an await the function's execution is "paused" (ie: suspended), so its waiting/suspended until the promise it's waiting on settles. It doesn't stop waiting after 5s. After 5s, all that happens is your setTimeout callback is executed and the code within that runs, but the promise continues to be in a pending state (as nothing resolved it and no errors occurred).
If hello() is suspended and stuck because the promise it's waiting on never settles, then the promise that hello() implicitly returns will also never settle, and so main() will be suspended at await hello()
Making stall() an async function won't really help or change much. If setTimeout() natively returned a promise then you'd be able to change it's implementation such that you await the setTimeout() call. But native JS doesn't have a "delay" or "wait" method that natively returns a promise, so you need to explicitly create your promise using new Promise() such that you can call resolve() once it executes its callback (as shown in the answer), otherwise, if you create an async promise that doesn't use await inside of it
all it will do is return a promise that resolves immediately (equivalent to doing function stall() { /* ... your setTimeout code ... */ return Promise.resolve()}, here Promise.resolve() just returns a Promise that resolves immediately, but that isn't really useful to the calling code of stall() as it doesn't provide any information about whether stall() has finished its asynchronous operation, and your setTimeout() would continue to run and wouldn't be linked to the resolution of the promise that had been returned.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.