Table of contents
![blog cover](https://namvo.net/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBLUT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c366b105d7f8a49c7e3a7b6958617b9e35c66bb6/js.jpg)
[PART 1] Unlocking JavaScript Interview: Promises and Timers
Web Development
Web Development
Interview
Interview
JavaScript interviews often include questions about asynchronous programming, as it's a fundamental concept in modern web development. One common challenge is understanding the intricate dance between Promises, timers, and the event loop.
The Challenge
Let's start with a tricky question that you might encounter in a JavaScript interview. Take a look at the following code and try to determine the order of the console.log outputs:
// language: javascript console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); process.nextTick(() => console.log('4')); new Promise((resolve) => { console.log('5'); resolve(); }).then(() => console.log('6')); console.log('7');
Take a moment to think about it. What order do you think the numbers will be logged?
The Answer and Explanation
1, 5, 7, 4, 3, 6, 2
Step-by-Step Analysis:
-
Synchronous Code Execution:
- console.log('1'); executes first and prints 1.
- console.log('5'); inside the new Promise executes next and prints 5.
- console.log('7'); executes and prints 7.
-
Asynchronous Code Scheduling:
- setTimeout(() => console.log('2'), 0); schedules a macrotask.
- Promise.resolve().then(() => console.log('3')); schedules a microtask.
- process.nextTick(() => console.log('4')); schedules a microtask. Note: process.nextTick has priority over other microtasks.
- The new Promise’s .then(() => console.log('6')); schedules a microtask.
-
Execution of Microtasks:
- Microtasks are executed after the current synchronous code completes but before any macrotasks.
- process.nextTick(() => console.log('4')); executes first and prints 4.
- Promise.resolve().then(() => console.log('3')); executes next and prints 3.
- new Promise().then(() => console.log('6')); executes last among microtasks and prints 6.
-
Execution of Macrotasks:
- The macrotask from setTimeout executes and prints 2.
Note: If you are seeing 1, 5, 7, 3, 6, 2, 4, it might indicate a difference in the environment where the code is being executed. Typically, process.nextTick should always execute before other microtasks like Promises.
![](https://namvo.net/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBLQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--defc7b156443fc1847b2d60e441357142280089d/task.gif)
Understanding Microtasks and Macrotasks in JavaScript
JavaScript is a single-threaded, non-blocking, asynchronous, concurrent language. This means that while JavaScript executes code on a single thread, it has mechanisms to handle asynchronous operations without blocking the main thread. Key to this functionality is the JavaScript Event Loop, which manages the execution of synchronous and asynchronous code. Within this system, tasks are categorized into two broad types: Microtasks and Macrotasks.
The JavaScript Event Loop
Before diving into microtasks and macrotasks, it's essential to understand the event loop. The event loop is responsible for executing the code, collecting and processing events, and executing queued sub-tasks. It continuously checks the call stack to see if there's work to be done.
When the call stack is empty, the event loop processes tasks from the task queues: the microtask queue and the macrotask (or task) queue.
Macrotasks
Macrotasks include events like setTimeout, setInterval, and I/O tasks. These are scheduled in the macrotask queue and executed one at a time. After each macrotask completes, the event loop will check the microtask queue and process all the microtasks before moving on to the next macrotask.
Examples of Macrotasks:
- setTimeout
- setInterval
- requestAnimationFrame
- I/O operations
Microtasks
Microtasks are tasks that are scheduled to run immediately after the currently executing script, but before any rendering and before any macrotasks. Examples of microtasks include promises (with .then and .catch handlers) and process.nextTick in Node.js. Microtasks are crucial for maintaining a smooth and responsive interface, as they are processed immediately after the current operation completes but before the browser has a chance to render.
Examples of Microtasks:
- Promises (.then, .catch, .finally)
- process.nextTick (Node.js)
- MutationObserver
The Order of Execution
Let’s break down the order of execution in the event loop:
- Execute synchronous code: Run all the code that is not inside any callback or asynchronous function.
- Process microtasks: After completing the synchronous code, the event loop will process all the tasks in the microtask queue before moving on to the next macrotask.
- Process macrotasks: Only after the microtask queue is empty will the event loop move on to the next macrotask.
Created at
2024-06-23 16:51:19 +0700
Related blogs
Exploring TypeScript Decorators
TypeScript, a statically typed superset of JavaScript, is a modern-age programming language that offers a wide array of advanced features. One of thes...
Web Development
Web Development
2024-04-03 22:56:46 +0700
[PART 1] Unlocking React Interview: Key Questions and In-Depth Answers
React.js is one of the most popular JavaScript libraries for building user interfaces. Whether you're a seasoned developer or just starting out, under...
Web Development
Web Development
Interview
Interview
2024-06-17 21:16:52 +0700