函数式触发click和点击触发click在宏任务与微任务方面的区别

在做关于事件循环的分享时,注意到了这两种方式的调用结果在宏任务和微任务的执行方面有差别,特此学习记录一下

用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 先通过点击执行
var btn = document.querySelector('#btn')
btn.addEventListener('click', ()=>{
Promise.resolve().then(()=>console.log("Microtask 1"));
console.log("Listener 1");
})
btn.addEventListener('click', ()=>{
Promise.resolve().then(()=>console.log("Microtask 2"));
console.log("Listener 2");
})
// Listener 1
// Microtask 1
// Listener 2
// Microtask 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 通过函数调用
var btn = document.querySelector('#btn')
btn.addEventListener('click', ()=>{
Promise.resolve().then(()=>console.log("Microtask 1"));
console.log("Listener 1");
})
btn.addEventListener('click', ()=>{
Promise.resolve().then(()=>console.log("Microtask 2"));
console.log("Listener 2");
})

btn.click();
// Listener 1
// Listener 2
// Microtask 1
// Microtask 2

说一下自己的理解,在网上找了好久,并没有一个确切的描述这种结果产生的原因。
上述两种结果的原因在于调用栈是否清空。也可以说是当前宏任务是否执行完毕。

点击触发

当我们通过addEventListener向按钮去添加事件时,实际上是添加在了其事件侦听器列表中,可以通过getListeners去查看所有的事件。

在直接点击DOM时,会向调用栈依次添加Listener,当第一个Listener执行完后,调用栈清空。此时在下一个Listener的添加/执行之前,会先处理微任务队列,从调用栈的角度看,两个Listener属于两个不同的宏任务。具体结果就是第一个例子的 Listener1、Microtask1、Listener2、Microtask2。

函数调用

在通过函数调用的时候,首先会向调用栈内添加click的调用,然后依次去执行该DOM上绑定的事件,在执行完第一个Listener中的事件后,没有return语句存在,所以click函数仍处于调用状态,调用栈并未弹出,在第二个Listener执行时仍处于同一个宏任务,所以也就有了下面的结果:Listener1、Listener2、Microtask1、、Microtask2。

补充

上述说明并没有很好的资料支持,是从输出结果Chrome控制台调用栈的显示反推的,如果有什么问题还请及时指出。

函数式触发click和点击触发click在宏任务与微任务方面的区别

http://example.com/2023/02/05/函数式触发click和点击触发click在宏任务与微任务方面的区别/

作者

徐云飞

发布于

2023-02-05

更新于

2023-02-05

许可协议

评论