字数
368 字
阅读时间
2 分钟
javascript
console.log('本轮任务');
new Promise((resolve, reject) => {
resolve(3)
}).then(() => {
console.log('本轮微任务');
})
document.getElementById('div').addEventListener('click', () => { console.log('click'); })
document.getElementById('div').click()
// 本轮任务
// click
// 本轮微任务解释 1
dom 事件的触发
- 从 web input 方式来的
- dispatch 的
- 代码 click 的
都会同步的调用到 xxxEventListener
由于 microtask 被调用的前提是嵌套调用栈必须是 0,仅有从 web input 方式来的是无包装调用,即 C++ 直接调用,未进行 JS 方法的包装 。
因此只有直接点击存在最初预计的情况,而 dispatch 的或者是 click 的方式都涉及到 JS 调用栈,即此例中 JS 存在 click 方法这一层调用栈深度,只有 click 内 fireEventListener 后,evt map 内的事件回调函数执行后,click 才是真正执行完成。
之后的 调用栈 才是 0,perform a microtask checkpoint 才能让 promise 方法执行完
解释 2
人工合成(synthetic)的事件派发(dispatch)是同步执行的,包括执行 click() 和 dispatchEvent() 这两种方式
上述代码就相当于执行了:
javascript
console.log('本轮任务')
queueMicrotask(() => console.log('本轮微任务'))
console.log('click')只有浏览器自己触发的事件才是放在一个 task 里执行的
扩展
- 几乎所有 dom 事件都是同步处理的
- 但是因为 js 的 run to completion 语义,对用户的输入响应只能是异步的