DEV Community

Cover image for JavaScript Asynchronous APIs: The Misconception That Confused Me
Tejas Khanolkar
Tejas Khanolkar

Posted on

JavaScript Asynchronous APIs: The Misconception That Confused Me

When I started learning JavaScript, I often heard things like:

  • setTimeout() is asynchronous.
  • fetch() is asynchronous.
  • addEventListener() is asynchronous.

After learning more deeply, I realized that this explanation is not completely accurate.

The real story is much more interesting.


The Question That Started It All

I was working with DOM methods like:

document.querySelector(".btn");
document.getElementById("title");
Enter fullscreen mode Exit fullscreen mode

These methods return elements immediately.

But then I noticed that methods like:

button.addEventListener("click", handler);
Enter fullscreen mode Exit fullscreen mode

use callbacks and seem asynchronous.

My question was:

If searching the DOM also takes time, why isn't querySelector() asynchronous?


Understanding the Difference

The answer is simple:

JavaScript treats operations differently depending on whether the result is available immediately or not.


Case 1: Result Is Available Immediately

Example:

const btn = document.querySelector(".btn");
Enter fullscreen mode Exit fullscreen mode

The browser already has the DOM tree in memory.

Something like:

Document
 ├── body
 │    ├── div
 │    ├── button.btn
 │    └── p
Enter fullscreen mode Exit fullscreen mode

When JavaScript asks for .btn, the browser searches the existing DOM structure and returns the element immediately.

JavaScript
     ↓
Find element
     ↓
Return element
     ↓
Continue execution
Enter fullscreen mode Exit fullscreen mode

Because the result is available immediately, JavaScript waits for it.

This is called synchronous execution.


Case 2: Result Depends on the Future

Now consider:

button.addEventListener("click", () => {
  console.log("Clicked");
});
Enter fullscreen mode Exit fullscreen mode

Here JavaScript is not asking:

"Give me something right now."

Instead it is saying:

"If a click happens in the future, run this function."

The click may happen:

  • 1 second later
  • 5 minutes later
  • never

JavaScript cannot stop and wait forever.

So the browser stores the callback and lets JavaScript continue running.


The Biggest Realization

I learned something surprising:

addEventListener() itself is not asynchronous.

The function call is synchronous.

button.addEventListener("click", handler);
Enter fullscreen mode Exit fullscreen mode

What happens:

Register event
      ↓
Return immediately
      ↓
JavaScript continues
Enter fullscreen mode Exit fullscreen mode

Later:

User clicks
      ↓
Callback executes
Enter fullscreen mode Exit fullscreen mode

The callback execution is asynchronous.

The function call is not.


The Same Thing Happens With setTimeout

Consider:

console.log("1");

setTimeout(() => {
  console.log("2");
}, 1000);

console.log("3");
Enter fullscreen mode Exit fullscreen mode

Output:

1
3
2
Enter fullscreen mode Exit fullscreen mode

Many beginners think:

"setTimeout is asynchronous."

More accurately:

setTimeout() call       → synchronous
Callback execution      → asynchronous
Enter fullscreen mode Exit fullscreen mode

What actually happens:

Run setTimeout()
      ↓
Register timer
      ↓
Return immediately
      ↓
Continue running code
      ↓
Timer finishes
      ↓
Execute callback
Enter fullscreen mode Exit fullscreen mode

What About fetch()?

console.log("Start");

fetch("/users");

console.log("End");
Enter fullscreen mode Exit fullscreen mode

Output:

Start
End
Enter fullscreen mode Exit fullscreen mode

Why?

Because fetch() does not wait for the server response.

Instead:

Start network request
      ↓
Return Promise immediately
      ↓
Continue execution
      ↓
Response arrives later
Enter fullscreen mode Exit fullscreen mode

Again:

Function call     → synchronous
Result delivery   → asynchronous
Enter fullscreen mode Exit fullscreen mode

The Mental Model That Finally Made Sense

Instead of asking:

"Is this function asynchronous?"

Ask:

"Can this function produce its result immediately?"

If yes:

document.querySelector();
document.getElementById();
Object.keys();
Array.map();
Enter fullscreen mode Exit fullscreen mode

These are synchronous.


If the result depends on a future event:

setTimeout();
fetch();
addEventListener();
WebSocket();
Enter fullscreen mode Exit fullscreen mode

Then JavaScript registers the work and continues.

The result arrives later.


The Rule I'll Remember Forever

Most APIs that developers call "asynchronous functions" are actually:

Synchronous function calls
            +
Asynchronous result delivery
Enter fullscreen mode Exit fullscreen mode

Visualized:

Call Function
      ↓
Register Work
      ↓
Return Immediately
      ↓
JavaScript Continues
      ↓
Result Arrives Later
      ↓
Callback / Promise Runs
Enter fullscreen mode Exit fullscreen mode

Final Takeaway

The important distinction is not:

Synchronous Function
vs
Asynchronous Function
Enter fullscreen mode Exit fullscreen mode

The important distinction is:

Function Call
vs
When the Result Becomes Available
Enter fullscreen mode Exit fullscreen mode

Many JavaScript APIs execute synchronously when called, but their results become available asynchronously later.

Once I understood this, concepts like:

  • Event Listeners
  • Timers
  • Promises
  • Fetch API
  • Event Loop

became much easier to understand.

Top comments (1)

Collapse
 
tejas_khanolkar_473f3ed1a profile image
Tejas Khanolkar

if these content really helps you then pls like share and follow for more😁