事件是否在微任务中冒泡



点击后,输出1:

const myElem = document.getElementById("myElem")
myElem.addEventListener('click', () => queueMicrotask(() => console.log(1)));
window.addEventListener('click', () => console.log(2));
<button id="myElem">Click me</button>

如果用setTimeout替换queueMicrotask,则输出2,然后输出1。这意味着冒泡发生在微任务中,但不发生在宏任务中。

它是DOM规范的一部分,还是只是浏览器实现的细节?

在微队列任务中发生事件冒泡的唯一方法是从从微任务队列中运行的代码中对元素调度自定义事件,或者如果突变观察者从微任务中内部收到DOM已被修改的信号(使用"slotchhange"事件(。在这两种情况下,事件都是从正在执行的微任务中激发的,事件冒泡在JavaScript执行线程中同步发生。相反;"本地";事件由浏览器触发,并通过事件循环异步调用事件处理程序。

发布的事件场景中缺少的是,如果为同一类型的本机事件添加了多个事件处理程序,则处理程序将从事件循环中调用。因此,在处理程序调用的控件返回到事件队列之前,将执行处理程序排队的任何微任务。

通过对两个"事件流"的演示;点击";处理程序:

"use strict";
document.querySelector("div").addEventListener("click", click1);
window.addEventListener("click", click2 /*, {capture:true}*/ );
function click1(event) {
console.log("click1 called for div")
queueMicrotask( ()=> console.log("microtask1 executes"));
console.log("click1 exits");
}
function click2(event) {
console.log("click2 called for window")
queueMicrotask( ()=> console.log("microtask2 executes"));
console.log("click2 exits");
}
div {background-color: yellow}
<div>Click this div</div>
or click the window,

在冒泡发生后调用窗口处理程序之前,运行代码段并单击div以确认div处理程序已被调用、退出并运行其派生的微任务。请注意,尽管是从事件循环中调用的,但调用它们的顺序将取决于是否使用事件捕获(在代码段中注释掉(。

如果在帖子的第一次单击处理程序中将queueMicrotask替换为setTimeout,则回调函数在返回事件循环之前将不再在微任务队列中执行,从而允许事件循环在计时器回调之前调用第二次单击处理程序(针对计时器到期前生成的事件(。

顺序的差异与事件冒泡无关之所以会发生这种情况,是因为setTimeout——就像单击侦听器本身一样——使其匿名函数的执行等待(至少(事件循环的一次完整迭代。queueMicrotask的好处是避免了这种额外的延迟。

这可能有助于澄清过程:

const
betweenTasks = (msg) => queueMicrotask( ()=>console.log(msg) ),
futureTask = (msg) => setTimeout( ()=>console.log(msg), 0),      
myElem = document.getElementById("my-elem");
myElem.addEventListener("click", () => {
futureTask("callbacks to `setTimeout` must wait additional iteration(s)");
betweenTasks("microtasks run between tasks");
console.log("callbacks to event listeners must wait in the task queue");
});
window.addEventListener("click", () => {
console.log("bubbled callbacks happen later than direct-target callbacks");
});
<button id="my-elem">Click me</button>

最新更新