52

I was reading Don't Block the Event Loop from the Node.js guide. There was a line saying:

You should make sure you never block the Event Loop. In other words, each of your JavaScript callbacks should complete quickly. This of course also applies to your await's, your Promise.then's, and so on.

I started to wonder, what if, some API call to the database which I'm awaiting is taking some time to resolve, does that mean that I have blocked the event loop with that await call?

After that, I started testing some self written codes but after testing I'm still not clear how blocking through await works. Here are some testing codes:

Assuming, that I'm using express for testing. I understand why making 2 API calls to the /test route blocks the event loop in this case.

function someHeavyWork() {
  // like calling pbkdf2 function
}

app.get('/test', (req, res) => {
  someHeavyWork();
  res.json(data);
});

But that doesn't happen in this case.

function fakeDBCall() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(data);
    }, 5000)
  })
}

app.get('/test', async (req, res) => {
  const data = await fakeDbCall();
  res.json(data);
})

This may be because of my lack of understanding of how blocking works in the case of async/await.

0

2 Answers 2

114

Contrary to what it seems, await does not block. It's just syntactic sugar over promises. Nothing is blocked; it may look blocking to allow code to be synchronous, but that's just sugar over promises. For example, this may look synchronous:

const response = await fetch(…);
const json = await response.json();
const foo = JSON.parse(json); // Using json here, even though my request was async!

But it's not. Once you desugar it, all you get are promises, which are nonblocking:

fetch(…)
  .then(response => response.json())
  .then(json => {
    const foo = JSON.parse(json);
  });

It would be absolutely catastrophic if await were blocking. JavaScript runtimes are generally single threaded. That means user interaction and other processes would cease whenever you made a request or some other async operation such as using the filesystem. On a related note, this is, along with dynamic imports, are the main argument against top level await

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

4 Comments

Understood why the second call is not blocking the event loop. One quick question, when the promise resolves does the callback of then is pushed to call-stack by event loop, if not then how it got pushed to it?
@MohammadAziz Internally, await executes PerformPromiseThen which is basically just Promise#then. In the operation, a new Job is enqueued (with the callback). And those jobs are executed once the call-stack is empty (so by the event loop, pushing new jobs to the call stack once it is empty).
Also, in the first example, you have the advantaje to manipulate the response and json objects. I mean, iterating the objects or getting another information.
If your fakeDBCall has no CPU work and still taking 5s, it'll block sockets. If there is CPU work that takes 5s, await is not going to help you to unblock event loop. It'll block event loop at a point.
-2

The async function returns a promise and you are passing in the request and response, I would change the res.json(data) to return res.json(data)

When an async function returns a value the promise is resolved, if the function contains an error the promise is rejected to just for cleanliness returning the res.json(data) will resolve the function.

1 Comment

Doesn't answer the question

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.