文章目录
- 情景展示
- 情况一:用户点击页面触发
- 情况二:通过 js 触发点击
- 结果分析
- 情况一
- 情况二
其实这个谜底揭开之后,第一反应都是,哦~,非常简单,但是细节决定成败,我被这个细节毁掉了,所以仅以此篇记录我这次的“折戟沉沙”
情景展示
情况一:用户点击页面触发
btn.addEventListener('click', () => {Promise.resolve().then(() => {console.log('microtask-1')})console.log('点击了1')
})btn.addEventListener('click', () => {Promise.resolve().then(() => {console.log('microtask-2')})console.log('点击了2')
})
输出如图:
情况二:通过 js 触发点击
btn.addEventListener('click', () => {Promise.resolve().then(() => {console.log('microtask-1')})console.log('点击了1')
})btn.addEventListener('click', () => {Promise.resolve().then(() => {console.log('microtask-2')})console.log('点击了2')
})btn.click()
输出结果如图:
结果分析
情况一
两者不一致的原因其实也简单,用户点击触发的时候,并不在执行栈中发生具体的代码执行,仅仅是发送了一个点击事件而已,所以在第一个侦听器触发时,会打印点击1
,然后将 microtask-1
加入微队列,图解如下:
此时由于执行栈为空,那么就会立即取出微队列的任务进行执行,即输出microtask-1
,第二个侦听器同理,打印点击了2
,然后直接取出微任务执行,打印 microtask-2
情况二
通过 js 触发的点击事件,首先会在栈中加入一个 btn.click 的任务,执行侦听器1打印点击了1
之后,就会把macrotask-1
加入微队列,此时执行栈是存在任务的,所以不会直接取出微队列执行。
继续执行侦听器2,打印点击了2
之后,将macrotask-2
加入微队列,此时点击事件执行完成,执行栈就是空的,所以会直接取出微队列里面的任务执行,依次打印 macrotask-1、macrotask-2,图解如下: