In JavaScript, synchronous and asynchronous code refer to the way tasks are executed and handled. Before we are diving into Callbacks, Promises, Async Await let's understand the difference between these two concepts.
Synchronous code:
Basically it's a code that executed line by line. Each line waits to the previous one to complete. This means that the code is executed in the order that is written.
Example of Synchronous Code:
console.log('Start'); // This will run first
console.log('Hello World'); // This will run second
console.log('Finish'); // This will run third
However, if a task takes time, such as a long loop or a blocking operation (like file I/O or database access), it can cause delays in the entire application.
console.log('Start');
for (let i = 0; i < 1000000000; i++) {
// Simulating a long-running task
}
console.log('End');
The loop takes several seconds, the program will be "frozen" until it completes, making it unresponsive to user interactions or other events.
Asynchronous Code:
Asynchronous code allows JavaScript to start a task but not wait for it to complete before moving on to the next one. JavaScript can continue executing other tasks and come back to the asynchronous task once it's done.
Non-blocking - JavaScript has a single-threaded execution model, meaning it can only execute one task at a time. However, the event loop enables it to handle asynchronous tasks without blocking the main thread. It does this by delegating time-consuming operations (like network requests, file I/O, timers, etc.) to external APIs (e.g., Web APIs in the browser) or the environment (Node.js APIs). Once these tasks are completed, the event loop adds the results (callbacks or promises) back to the task queue or microtask queue for execution when the main call stack is clear.
Callbacks, Promises, and Async/Await are tools or mechanisms that enable us to work with asynchronous tasks more easily within this event loop model. They don't make JavaScript non-blocking on their own but help you manage the non-blocking behavior effectively.
console.log('Task 1'); // This will run first
setTimeout(() => {
console.log('Task 2'); // This will run after 3 second
}, 3000);
console.log('Task 3'); // This will run immediately after Task 1
Asynchronous code makes it possible to handle tasks like:
- Fetching data from a server.
- Waiting for a user input.
- Timers, like setTimeout or setInterval.
How the Event Loop works:
Call stack- Manages the execution of all functions in a single-threaded manner, using a stack to track function calls.
Web APIs- A set of functionality to interact with the browser features. When an asynchronous operation (like setTimeout or fetch) is invoked, it's handed over to the Web API.
Task queue/callback queue- Holds Web API callbacks, once the asynchronous operation completes, the associated callback is placed in the callback queue.
Event loop- Responsible to check if the call stack is empty. If the queue is empty it takes a task from the microtask queue, if the microtask is empty he taking tasks from callback queue.
Microtask queue- When we working with promises we are using the microtask queue. The event loop priorities the microtask queue. This is a special queue dedicated to the next callback:
.then(() => {...})
.catch(() => {...})
.finally(() => {...})
Function body after await
queueMicrotask(): This function explicitly adds a task to the microtask queue.
MutationObserver: This is another example of a mechanism that adds tasks to the microtask queue.
Async example:
console.log('Start');
setTimeout(() => {
console.log('Async Task Complete');
}, 1000); // Asynchronous operation, handled by Web API
console.log('End');
Execution flow:
console.log('Start')
runs first, logging "Start".setTimeout()
Registering to Web APIs, the asynchronous task is scheduled to move into the callback queue after 1 second and will log 'Async Task Complete' when the call stack is empty (note that it may take longer than 1 second if the call stack is not empty).console.log('End') runs immediately, logging "End".
After 1 second, the event loop pulls the callback from the callback queue and logs "Async Task Complete".
Top comments (0)