3
console.log("1");
  console.log("2"); 
async function a() {
    for (let i = 0; i < 1000000000; i++) {}
    for (let i = 0; i < 1000000000; i++) {}
  }
  a().then(() => console.log("in then"));

  console.log("3!");

This output I want is this 1 2 3! in then

but the async function behaves synchronously and does not let the 3! print until after the long loops are done executing. I thought if the async keyword is used, it runs the function inside in the background? I basically want the 2 long loops to run in the background. Just trying to understand async and await. Thanks.

Edit: could someone tell me why this also works synchronously??

  console.log("2");

  function lag(resolve) {
    for (let i = 0; i < 1000000000; i++) {}
    for (let i = 0; i < 1000000000; i++) {}
    console.log("in lag");
    return resolve;
  }
  async function a() {
    // console.log("its done");
    let a = await new Promise((resolve, reject) => lag(resolve));
  }
  a().then(() => console.log("in then"));

  console.log("3!"); ```

2
  • for is totally synchronous. You are executing a very CPU-intensive operation, there's nothing asynchronous in it. Remove the async keyword, it's totally useless. Commented May 2, 2021 at 8:22
  • "thought if the async keyword is used, it runs the function inside in the background?" no, that's not true and has never worked like that. async does not spawn a new process. It only allows you to use await in the body and then returns a promise. It does automatically handle promise sequencing but it's still all a single thread. Commented May 2, 2021 at 8:29

1 Answer 1

11

There is nothing about async functions (or promises) that makes anything run in the background. They don't create a new thread or anything like that.

An async function is synchronous until the first await or return. Since your function doesn't have any await or return, it's fully synchronous.

The purpose of promises is to observe the completion of something that's already asynchronous, such as the browser's loading things via HTTP, or a timer. The purpose of async functions is to have syntax for using promises that lets us write the logical flow of the code rather than writing callback functions. Neither of them makes anything asynchronous, or moves things to a different thread.

If you want to run something in the background, you can create a worker thread and exchange information between it and the main thread via messaging. On browsers it's web workers. In Node.js it's the worker threads module.

In your question and in comments on the answer you've talked about how an async function seems to wait for an asynchronous task to complete. And indeed, the logic of the function does. But that's really syntactic sugar for using promises (really, really good syntactic sugar, IMHO). Let's look at an async function:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function example() {
    // The function starts out synchronous, so that it can
    // start whatever inherently-asynchronous thing it does
    // (like calling `fetch`).
    console.log("[example] This is synchronous");

    // When execution reaches the first `await` or `return`,
    // the `async` function returns a promise. The synchronous
    // part of its work is now complete.
    await delay(10);

    // This code runs later, when/if the promise from `delay`
    // is settled.
    console.log("[example] This is asynchronous, but still on the main thread");

    // If you `throw` in an `async` function, it rejects the `async`
    // function's promise.
    if (Math.random() < 0.5) {
        throw new Error("Error thrown by `example`");
    }

    // The "return" value of an `async` function is the fulfillment
    // value of the promise the `async` function returned
    return 42;
}

console.log("[top] Calling `example`...");
const promiseFromExample = example();
console.log("[top] Back from calling `example`. Waiting for its promise to settle.");
promiseFromExample
.then((value) => {
    console.log(`[top] The promise from \`example\` was fulfilled with the value ${value}`);
})
.catch((reason) => {
    console.log(`[top] The promise from \`example\` was rejected with the rejection reason ${reason.message}`);
});
.as-console-wrapper {
    max-height: 100% !important;
}

Run that a few times so you see both a fulfillment and a rejection (each run has a 50/50 chance). Nothing in that code runs anywhere but the main thread, it's just that with await, the logic in example can wait for a promise to settle. The promise from delay lets us observe the completion of the timer, then example awaits that completion before continuing its logic.

The key things are:

  • Promises don't make anything asynchronous¹
  • Promises and async functions don't move anything off the main thread
  • async functions always return promises
  • The code in an async function runs synchronously until the first await or return
  • The promise from an async function gets fulfilled with the return value of the function, or rejected with any error that occurs in the function

¹ Okay, there's one caveat to that: If you use .then or .catch (or .finally) to hook up a callback to a promise, that callback will always be called asynchronously, even if the promise is already settled.

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

3 Comments

FWIW, I go into promises in detail in Chapter 8 and async functions in detail in Chapter 9 of my recent book JavaScript: The New Toys. Links in my profile if you're interested.
Hi thanks and I'm interested in checking that chapter. So if I want a set of instructions that may take more than a few cpu ticks to execute run asynchronously how should I implement it in js? by using await? In the code I posted above, how can I make the "3!" print in the console immediately after "2"? I understood the web workers but I've noticed fetch operations holding up execution of instructions written under them working asynchronously to avoid making the instructions under it wait. is something like that possible for instructions I can write?
@TheSlyOne - The only way to have CPU-intensive code not block the main thread is to put it on another thread -- a worker thread. Neither promises nor async functions do that for you. The reason fetch is asynchronous is that the browser handles doing the HTTP request by just having fetch start the process, returning a promise, and later fulfilling or rejecting that promise when it has the result. An async function using fetch is basically only asynchronous because fetch is. I've expanded the answer to try to illustrate that a bit. Happy coding!

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.