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.
답글 남기기