When the click event is fired from the mouse, it behaves as expected:
First the listener 1 is pushed into the stack where it queues promise 1 in Microtask Queue(or Job Queue). When listener 1 is popped off, the stack becomes empty. And the promise 1 callback is executed before the listener 2(which is waiting in the Task Queue(or Callback Queue). After promise 1 callback is popped off, the listener 2 is pushed into the stack. So the output is :
Listener 1 Microtask 1 Listener 2 Microtask 2
However when the click is triggered via JavaScript code, it behaves differently:
The callback is pushed into the stack even before the click() function is completed (i.e. call stack is not empty). The output here is :
Listener 1 Listener 2 Microtask 1 Microtask 2
Here's the code:
window.onload = function(){
document.getElementById("myBtn").addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 1'));
console.log('Listener 1');
} );
document.getElementById("myBtn").addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 2'));
console.log('Listener 2');
} );
}
function clickB(){
document.getElementById("myBtn").click();
}
<!DOCTYPE html>
<html>
<button id="myBtn">Manual Click</button>
<button onclick="clickB()">JS Click</button>
</html>
My understanding is that items from Task Queue and Microtask Queue only get pushed into the Call Stack when it's empty. I might have made wrong assumptions. Please feel free to correct me. Thank you
click()
is a wrapper arounddispatchEvent
- which gets a return value from the event handlers, so it's clearly not queueing a task. Try adding twoconsole.log()
statements around the.click()
call and it'll become clear. – Arrhenius