Synchronous vs Asynchronous JavaScript
When I was only a few days into programming, I believe it was BASIC, I believed I understood how the code executed and how the data flowed. I was naive enough to believe that, and remember some BASIC versions required us to manually number code statements, the programme executes just as we have created or structured them. That the very first line would execute first, followed by the statement after it and so on and so forth.
Oh, how naive I was.
Synchronous and Not-Synchronous
In most of our childhood days of learning to programme, we start out with basic conditionals or loops and when executed our code runs line-by-line. Upon this behaviour no one bats an eye, after all this feels intuitive. The code should run line by line after all.
Synchronous code behaviour is when the code written executes line-by-line top to bottom way. We are concerned with one step at a time.
- The code might look something like this:
//1.
const name = `Jay`;
//2.
let age = 8;
//3.
while(age < 18)//3.1{
console.log(`${name} cannot vote right now`);//3.2
age++;//3.3
}
//4.
console.log(`${name} is now allowed to vote and to apply for driver's license`);
In the above Javascript code, the
1. line executes first and a variable is initialized and its value is stored in the memory.
2. Another variable is initialized and its value is stored too.
3. A loop is run and while there are a lot of internals going on in the background for the sake of understanding we simply say a condition is checked in 3.1, followed by execution of console.log() statement. After which we increase the value of age variable in line 3.3. The loop however continues to run until the condition specified in line 3.1 is met.
4. After the loop has run its course, the line 4 is executed.
This right here is Synchronous Code.
The Issue
This behaviour of execution of programmes is completely viable for early days but as soon as we move from simple programmes in our local high spec environment to something on a global level, cracks begin to appear.
Let us assume that we've built a website, a beautiful website adorned with bleeding edge animations. We are happy with our work. But just the next day users' mail pile up with one issue the website freezes almost all the time any animation starts, well animating. The data is blocked several times due to the synchronous nature of the code and of the Javascript.
If this behaviour of performance persists, you might as well simply mail your users "FAFO", Find Another Future Option.
The solution to such is Non-Synchronous or better known as,
Asynchronous Code
By default, Javascript is a single-threaded language, which means the entire execution of code is handled by a single thread and what it results to is one thread handling calculations, handling user data, displaying elements. This is too much for one thread to manage at once. Hence, at one time it can only execute one task. We can not have that in modern web, no no no no no. Hence non-blocking or asynchronous code.
In our beloved beautifully animated website example, Let's say we fixed the code and now as soon as the main thread encounters an animation it simply delegates that task to another worker thread instead of handling it by itself. This way, we obtain a smooth User Experience.
In the asynchronous code, the code instead of being executed line-by-line executes on the basis of availability. If a code requires some time to be executed, a worker thread handles it in the background while main thread executes the code at hand.
Why JavaScript Absolutely Needs Asynchronous Behavior
The web is inherently unpredictable. When you request data from a server (like loading a user's Instagram feed or fetching weather data), you have no idea how long it will take. It could take 50 milliseconds, or it could take 5 seconds if their connection is slow.
If JavaScript didn't have asynchronous capabilities, every single network request would freeze the browser. Asynchronous code allows the browser to say, "Hey, go fetch that data from the server, and let me know when you have it. In the meantime, I'm going to finish rendering this cool animation."
Some Asynchronous Works
2 of the most used asynchronous code in the world:
1. Timers (setTimeout):
Timers tell JavaScript to wait a certain amount of time before running a block of code, but they do it asynchronously.
JavaScript console.log("1. Order placed");
setTimeout(() => { console.log("2. Food is ready!"); }, 3000); // Wait 3 seconds
console.log("3. Taking the next customer's order"); What you will see in the console: 1. Order placed 3. Taking the next customer's order (...3 seconds later...) 2. Food is ready!
Notice how Step 3 didn't wait for Step 2? That’s non-blocking code in action.
2. API Calls (fetch):
When you request data from another computer over the internet, you use an API call.
JavaScript console.log("1. Requesting user profile...");
// This network request happens in the background
fetch('https://api.example.com/user') .then(response => response.json()) .then(data => { console.log("3. Profile loaded: ", data.name); });//Now we wait... wait... wait...
console.log("2. Rendering the rest of the webpage...");
What you will see in the console:
➡️ 1. Requesting user profile...
➡️ 2. Rendering the rest of the webpage... (...whenever the server responds...)
➡️ 3. Profile loaded: Jane Doe
How Async tasks are handled
The Regular Line (Task Queue / Macrotasks) Think of the Task Queue as the standard waiting room. This is where "slower" async tasks go once they are finished and ready to be processed.
- Examples: setTimeout, setInterval, and I/O operations (like clicking a button).The Rule: The doctor will only look at this waiting room once their current appointment is totally finished and the office is empty.
The VIP Line (Microtask Queue) Not all tasks are created equal. JavaScript has a "Fast Pass" lane called the Microtask Queue.
- Examples: Promises (the .then() blocks) and queueMicrotask.The Rule: This line has absolute priority.
How Priority Works (The Event Loop) The Event Loop is like the office manager who decides who the doctor sees next. Here is the strict order of operations:
Clear the Main Thread: The doctor finishes the current task.
Check the VIPs (Microtasks): The manager looks at the Microtask Queue. If there are 10 Promises waiting, the doctor sees all 10 of them one after another before even looking at the regular waiting room.
Check the Regulars (Macrotasks): Only when the VIP line is completely empty does the manager pick one task from the regular Task Queue.
Repeat: The cycle starts all over again.
Why this matters: If you have a Promise and a setTimeout finishing at the exact same time, the Promise will always run first. The Microtask Queue is effectively "selfish"—it will keep the doctor busy as long as there are VIPs waiting, even if the regular patients have been sitting there for a while!
So basically, Main Thread(First), Promises(Second), and Timers(Last).
Conclusion
This topic couldn't be contained in one or two articles as this spans up numerous functions. But this shall be a great start in the deep series of js internals.



