1

=== update on Aug 18th, 2023

.click() is synchronous

(I've made a mistake in my previous code snippet,

the callback in the Promise constructor also runs synchronously)

if I add one line of Promise.resolve().then(() => console.log('then')), everything make sense!)

=== I've read lots of articles about event loop, but seems a few of them mentioned that is a DOM event handler a micro or a macro task?

and I was trying to figure it out by code, but something weird happened.

document.querySelector('#btn2').addEventListener('click', () => {
  console.log('click btn2')
})

document.querySelector('#btn1').addEventListener('click', () => {
  console.log('click btn1')
  setTimeout(() => console.log('timer'));
  new Promise(res => { console.log('promise');res(); });
  document.querySelector('#btn2').click();
})
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>

in this snippet, the console output is

click btn1
promise
click btn2
timer

so it seems to tell DOM event handler is a microtask

but when I adjust the line order in the code, I move the .click() to the top

document.querySelector('#btn2').addEventListener('click', () => {
  console.log('click btn2')
})

document.querySelector('#btn1').addEventListener('click', () => {
  document.querySelector('#btn2').click();
  console.log('click btn1')
  setTimeout(() => console.log('timer'));
  new Promise(res => { console.log('promise');res(); });
})
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>
the output is:
click btn2
click btn1
promise
timer

the click event runs before the sync code?

can someone explain this to me, thanks

Littlee
  • 3,791
  • 6
  • 29
  • 61
  • 1
    The browser does not have to guarantee that asynchronous code executes in the order you wrote them. Especially if you bring `setTimeout` and `Promise` into the mix. Those are executed asynchronously and your output in the console may be more incidental and less causational. – Peter Krebs Aug 17 '23 at 08:55
  • 2
    `click()` produced by a program is not actually the same as manual click. – Jaood_xD Aug 17 '23 at 08:56
  • 3
    Everything is synchronous in your code, except the timer. That's why outputs follow code-order, except the timer, that always comes last. You can go to `click()` on MDN, and then follow the specification https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click#specifications – tevemadar Aug 17 '23 at 08:59
  • 3
    Very relevant: [Is triggering event listeners using ".click()" synchronous?](https://stackoverflow.com/q/33621545) – VLAZ Aug 17 '23 at 09:52
  • @PeterKrebs asynchronous execution does not mean "random order" `setTimeout() => console.log(1)); setTimeout() => console.log(2)); setTimeout() => console.log(3));` will always run asynchronously but would ***never*** produce a sequence other than 1 -> 2 -> 3. The execution of `setTimeout` and promise followups in particular are via macro/microtask queues which is also not quite random. As long as the async tasks take no real time, the results are predictable. However, there is largely no guarantee if they do take some time, e.g., AJAX requests, calls to database, etc. – VLAZ Aug 17 '23 at 09:56
  • @VLAZ almost a dupe, assuming the `Promise`-callback-runs-on-spot is known to OP. – tevemadar Aug 17 '23 at 13:25
  • Also relevant for "native" events: https://stackoverflow.com/questions/76673558/what-is-the-priority-of-eventlistener-callback-functions-in-the-event-loop/ – Kaiido Aug 18 '23 at 02:28

0 Answers0