karjan
karjan

Reputation: 1016

Invoking synchronous function in asynchronous function

I have problem understanding how async function work in JavaScript. Let's take the code below:

async () => {
      console.log(1);
      setTimeout(() => console.log(2)
        , 2000)
      console.log(3);
}

I would expect that invocation of synchronous function inside async should block thread before executing further code. So I'd expect to get 1 -> 2 -> 3 instead I'm getting 1 -> 3 -> 2. Can't find explanation why it's happening and how to block thread to receive output 1 -> 2 -> 3. I'm using Node 12 with serverless framework.

Upvotes: 1

Views: 328

Answers (2)

norbitrial
norbitrial

Reputation: 15166

async itself won't wait until execution of setTimeout finished as you expect. As you can read from the documentation - find here for async:

An async function can contain an await expression that pauses the execution of the async function to wait for the passed Promise's resolution, then resumes the async function's execution and evaluates as the resolved value.

Just built a quick example to see the difference between async and await solution and just using setTimeout as it is in your example.

Consider the following example:

const getPromise = async () => {
  return new Promise((resolve) => {
    setTimeout(resolve, 3000);
  });
}

const run = async () => {
  console.log('run started');
  setTimeout(() => console.log('setTimeout finised'), 2000);
  console.log('setTimeout started');
  const promise = await getPromise();
  console.log('Promise resolved');
  console.log('run finished');
}

run();

Steps explained:

  1. Logging that function run execution started
  2. Attaching an event to setTimeout which will be finished in ~2 seconds
  3. Log into console that setTimeout started
  4. Creating promise with getPromise function and with await keyword wait till resolve
  5. In ~2 seconds setTimeout logs that it has been finished
  6. In ~3 seconds from Promise the resolve function called
  7. run function finishes its execution after resolve and logging.

I hope that helps you understand this portion of the code.

Upvotes: 1

Quentin
Quentin

Reputation: 944456

I would expect that invocation of synchronous function inside async should block thread before executing further code.

It does

So I'd expect to get 1 -> 2 -> 3 instead I'm getting 1 -> 3 -> 2.

setTimeout is not synchronous. It very explicitly is for queuing up a function to run later, after some time has passed.

Can't find explanation why it's happening and how to block thread to receive output 1 -> 2 -> 3.

You can't per se.

The closest you could come would be to replace setTimeout with a loop that runs around in circles until some time has passed… but that would be awful (it would lock up the UI for starters).

If you want to just run the three logs in order, then replace setTimeout with something that returns a promise and then await it (which would put the async function to sleep and let any other code continue to run until the promise resolved).

const timeout = function() {
  return new Promise(function(res) {
    setTimeout(() => {
      console.log(2);
      res();
    }, 2000)
  })
};


const x = async() => {
  console.log(1);
  await timeout();
  console.log(3);
}

x();

Upvotes: 1

Related Questions