Microtask Queue
Promises/Async/Await: Microtask Queue
What is the Microtask Queue in JavaScript?
View Answer:
How does the Microtask Queue differ from the Task Queue?
View Answer:
What is the role of Promises in the Microtask Queue?
View Answer:
Can you explain how the Microtask Queue is processed?
View Answer:
What is the purpose of the queueMicrotask() function?
View Answer:
Let's say we want to defer a piece of code until the current task and all other microtasks have completed. We can use queueMicrotask()
for this purpose:
console.log('Script start');
queueMicrotask(() => {
console.log('Microtask 1');
});
queueMicrotask(() => {
console.log('Microtask 2');
});
console.log('Script end');
// Output:
// Script start
// Script end
// Microtask 1
// Microtask 2
In the example above, 'Script start' and 'Script end' are logged first. Even though we queued two microtasks, they don't run until after the script has completed.
Can you explain how the Job Queue (Microtasks Queue) works?
View Answer:
console.log('Message no. 1: Sync');
setTimeout(function () {
console.log('Message no. 2: setTimeout');
}, 0);
var promise = new Promise(function (resolve, reject) {
resolve();
});
promise
.then(function (resolve) {
console.log('Message no. 3: 1st Promise');
})
.then(function (resolve) {
console.log('Message no. 4: 2nd Promise');
});
console.log('Message no. 5: Sync');
// Expected Output:
// Message no. 1: Sync
// Message no. 5: Sync
// Message no. 2: setTimeout
// Message no. 3: 1st Promise
// Message no. 4: 2nd Promise
How can we make code run after a promise completes if the order matters to us?
View Answer:
Promise.resolve()
.then(() => console.log('promise done!'))
.then(() => console.log('code finished'));
When does an unhandled rejection occur in JavaScript promises?
View Answer:
let promise = Promise.reject(new Error('Promise Failed!'));
promise.catch((err) => console.log('caught'));
// doesn't run: error handled
window.addEventListener('unhandledrejection', (event) => console.log(event.reason));
//////////////////////////////////////
// Example: if we don't handle our errors
let promise = Promise.reject(new Error('Promise Failed!'));
promise.catch((err) => console.log('caught'));
// doesn't run: error handled
window.addEventListener('unhandledrejection', (event) => console.log(event.reason));
//////////////////////////////////////
// Example: if we handle errors later in our code
let promise = Promise.reject(new Error('Promise Failed!'));
setTimeout(() => promise.catch((err) => console.log('caught')), 1000); // handling error 1 second later
// Error: Promise Failed!
window.addEventListener('unhandledrejection', (event) => console.log(event.reason));
Can the Microtask Queue be blocked by long-running synchronous code?
View Answer:
console.log('Script start');
const start = Date.now();
while(Date.now() - start < 5000) {} // long-running synchronous code, blocks for 5 seconds
queueMicrotask(() => {
console.log('Microtask executed');
});
console.log('Script end');
// Output:
// Script start
// Script end (after 5 seconds)
// Microtask executed
In this example, the microtask is blocked by the long-running synchronous while loop and only executes after that code completes.
What happens if a microtask enqueues another microtask?
View Answer:
What is the difference between using setTimeout() and queueMicrotask() to schedule a task?
View Answer:
console.log('Script start');
setTimeout(() => {
console.log('Macrotask: setTimeout callback');
}, 0);
queueMicrotask(() => {
console.log('Microtask: queueMicrotask callback');
});
console.log('Script end');
// Output:
// Script start
// Script end
// Microtask: queueMicrotask callback
// Macrotask: setTimeout callback
Even though setTimeout
is called before queueMicrotask
, the microtask executes first. This is because the Microtask Queue is processed immediately after the current task completes and before returning to the event loop, whereas setTimeout
schedules a macrotask, which will only execute after control returns to the event loop.
How does the MutationObserver API use the Microtask Queue?
View Answer:
Here's an example. Let's say we want to watch for changes to a DOM element. We can use the MutationObserver
API for this purpose, and its callbacks will be queued in the Microtask Queue:
let div = document.createElement('div');
let observer = new MutationObserver(() => {
console.log('Mutation observed');
});
observer.observe(div, { attributes: true });
console.log('Script start');
div.setAttribute('id', 'test');
console.log('Script end');
// Output:
// Script start
// Script end
// Mutation observed
In this example, even though the mutation (the attribute change) happens before 'Script end' is logged, the callback isn't called until after the script completes, demonstrating that MutationObserver uses the Microtask Queue.