浏览器事件触发机制是一种异步执行机制
主要涉及到以下几个阶段
- 捕获阶段:在这个阶段,事件从最外层 HTML 元素向下传递到事件的目标元素,沿途触发所有设置了捕获事件处理器(通过
addEventListener
设置第三个参数为true
)的元素。 - 目标阶段:在这个阶段,事件处理器将在事件的目标元素上执行。这是事件处理的核心阶段,可以访问事件对象的所有属性和方法。
- 冒泡阶段:在这个阶段,事件从事件的目标元素向上回溯,沿途触发所有设置了冒泡事件处理器(默认情况下)的元素。
这种机制允许开发者在事件传播的不同阶段拦截并处理事件。例如,如果你希望在某个元素内部阻止特定事件的发生,你可以在捕获阶段处理事件,而不是冒泡阶段,这样可以防止事件进一步传播。 此外,浏览器还会有一个事件队列(Event Queue)。当事件发生时,浏览器会把它们放到事件队列中,等待处理。一旦事件队列中的事件得到处理,它就会被移除。
例如,当你点击一个按钮时,浏览器会首先触发捕获阶段,然后到达目标阶段,最后进入冒泡阶段。在这个过程中,如果有其他事件发生,比如定时器触发,那么这些事件会被放在事件队列中,等到前面的事件完全处理完毕后再进行处理。
浏览器微任务执行优先级
浏览器的任务调度有几种不同的优先级,包括宏任务(macro task)、微任务(micro task)和用户交互任务(interactive task)。 宏任务包括脚本执行、网络请求、setTimeout 和 setInterval 等,这些任务通常需要消耗较多的时间和资源,因此它们的执行优先级较低。 微任务包括 Promise、MutationObserver 和 process.nextTick 等,这些任务通常比较轻量,它们会在当前宏任务执行完毕后立即执行。 用户交互任务包括鼠标点击、键盘输入等,这些任务的优先级最高,它们会被立即执行。 一般来说,浏览器的事件循环会按照以下顺序执行任务:
- 用户交互任务
- 微任务
- 宏任务
但是,实际上浏览器的事件循环是由很多细节组成的,不同浏览器可能会有不同的实现。例如,Chrome 和 Firefox Firefox 在宏任务和微任务之间插入了渲染任务,这使得它们的事件循环更加复杂。 总的来说,理解这些任务调度规则有助于更好地理解和优化 Web 应用的性能。