If Javascript is single-threaded, how can ‘await’ wait ?

If Javascript is single-threaded, how can ‘await’ wait ?

The Illusion of Waiting

When developers first see await, it feels like Javascript is waiting for a result. BUT IS IT ?

Lets look at following code :

function fetchData() {
	return new Promise.resolve('some data');
}

async function doo() {
	const data = await fetchData();
	console.log(data);
	//rest of code
}
console.log('before doo() call');
doo();
console.log('after doo() return');

Lets focus inside doo() function

...
async function doo(){
  const data = await fetchData();
  console.log(data);
  //rest of code
}
...
  • code looks synchronous, it appears as if the program pauses at await until the data arrives
  • But Javascript is single threaded, and if it truly waited, the entire application would freeze, the UI would stop responding.

Confusing right ? Does Javascript waits or not ?

The Reality: JavaScript Is Not Waiting

‘await’ pauses the function, not the thread.

  • The code after await becomes a microtask,
  • that runs whenever the Promise is resolved.

Lets run the above code line by line:

  1. Synchronous code starts :
    console.log('before doo() call')
    Prints : before doo() call

  2. Calls doo() : Thread is still executing synchronously,
    It hits await fetchData(); The remaining code after await is scheduled as a microtask.
    As a result the function pauses, it syncronously returns to the caller.

  3. Continue after the call
    console.log('after doo() return')
    Prints : after doo() return

  4. Call stack empties, microtasks run :
    Call stack becomes empty.
    The Event Loop processes the microtask queue where remaining portion of doo() is ready to be executed. console.log(data);
    Prints : some data

Output :

Think of it like this : await transforms the function into:

function doo(){
 fetchData().then((data) => {
  console.log(data)
  // rest of code
 })
}

Of course, this transformation is only a mental model, not the exact implementation.
But it explains the core idea clearly.

await basically, “splits the function into two parts”
Before await → run now
After await → run later (microtask)

Mental Model: Bookmarking a Chapter

Think of a function as a chapter in a book.
When JavaScript reaches await in a chapter

  • it places a bookmark in the chapter
  • leaves the chapter for now
  • continues reading other chapters (running other code)
  • comes back to the bookmarked page when the Promise resolves

‘await’ doesn’t stop the reader (the JavaScript thread).
It just bookmarks the chapter and resumes it later.

References

Author’s Notes

I enjoy breaking down complex Javascript and algorithms into simple mental models.

If you found this useful, feel free to connect or share your thoughts by connecting with me on linkedin