事件冒泡是宏任务还是微任务,以及冒泡的触发时机?

之所以想到这个问题,是因为在看一篇介绍事件循环的文章的一个例子

<div class="outer">
  <div class="inner"></div>
</div>
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

function onClick() {
  console.log('click');
  
  setTimeout(function() {
    console.log('setTimeout');
  }, 0);

  Promise.resolve().then(function() {
    console.log('new Promise');
  });
}

inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

执行结果是

click
new Promise
click
new Promise
setTimeout
setTimeout

关于事件循环、宏任务、微任务我已经比较了解。但是这些内容和事件冒泡、捕获的传递结合起来,之前没有考虑过。

文章开头介绍宏任务包括“UI交互事件”,所以点击事件是宏任务

但从执行结果来看,事件冒泡是属于微任务。当然,一个是事件的点击,一个是事件的传递,性质不同。不知道官方标准是怎么定义这部分内容的?另外,和这个有关的标准,是定义在JS,DOM?还是浏览器自己决定如何实现?

另外,关于冒泡的触发时机的问题,如下哪个先执行?

  • 执行inner的事件处理函数
  • 把 "click事件要冒泡" 添加到事件队列
阅读 2.7k
2 个回答

冒泡是否算执行任务?

理论来说,事件冒泡本身 不属于 宏任务或微任务,但事件的处理可以在宏任务或微任务中进行。

宏任务( macrotasks )和微任务( microtasks )都是 js 的 执行机制 中的概念,而事件冒泡是一个 事件模型

在 W3C 的事件模型中,当一个元素接收到事件的时候,会把它往上冒泡,会一直冒泡到 document 对象,这个行为本身和 js 无关,js 只负责捕获和处理

ECMAScript没有 明确定义事件处理过程中各个阶段(捕获、目标和冒泡)是否属于宏任务或微任务。

更何况不同浏览器对于冒泡执行顺序的定义也 不完全一致
不同浏览器事件冒泡

冒泡的触发时机?

如果题主特别感兴趣,推荐看后文参考第二篇 Jake Archibald 的文章,里面有对冒泡以及执行顺序的流程图,可以一步步自己调试

一般来说,冒泡按照捕获阶段、目标阶段和冒泡阶段的顺序依次触发相应的事件处理程序

当你点击元素时,监听事件捕获到后首先会添加一个执行冒泡点击元素的事件处理函数到任务队列,然后这个事件处理函数将在当前宏任务执行完后的下一个宏任务执行

但是冒泡是浏览器的 默认行为 ,并 不需要 添加到任务队列,它会立即开始,并在所有的同步任务完成后和下一个宏任务开始前完成。

所有监听器被触发是同步的,不会放到任务队列中,硬要说的话,冒泡过程和其对应的事件处理函数的触发是在 同一个 任务中完成的

参考
Flavio Copes - The JavaScript Event Loop
Jake Archibald - Tasks, microtasks, queues and schedules

下面这俩是油管视频,观看需要浅翻一下
Anjana Vakil - The JavaScript Event Loop: Explained
Philip Roberts - JSConf on the event loop

推荐问题
宣传栏