繁体   English   中英

在浏览器中触发事件时,事件处理程序在什么时候确定?

[英]At what point do the event handlers get determined when an event has been fired in the browser?

我最近阅读了很多关于事件循环和它所具有的不同队列(作业/宏任务队列、微任务队列、渲染队列)及其优先级的信息。 但是我仍然无法完全理解一件事,假设用户一个接一个地快速触发 2 个事件。 然后两个事件处理程序将被排入作业队列并以正确的顺序执行。 但是,如果第一个事件处理程序进行了一些繁重的计算并阻塞了主线程一段时间,但它也以改变 UI 的方式操作 DOM,以便用户第二次单击的元素被删除并替换为一些其他也注册了点击事件的 dom 元素。

然后,如果我正确理解了这个过程,一旦第一个事件处理程序完成执行,所有微任务都会被执行并且微任务队列被清空。 然后渲染队列被清空,浏览器重新绘制。 这是我的实际问题,第二个事件处理程序是根据 UI 的新状态执行,还是根据单击时存在的元素执行?

我尝试了这一点( https://jsfiddle.net/jsx73t6c/4/ ),每个按钮都有一个注册了单击事件处理程序的按钮,该处理程序记录到单击相应按钮的控制台。 我在按钮 1 和按钮 2 上快速单击。按钮 1 的处理程序执行一个大循环,因此主线程被阻塞一段时间,然后删除按钮 2。由于按钮 2 被删除,它的位置是按钮 3,我最终得到 2控制台日志指示按钮 1 和按钮 3 已被单击,即使在单击我的鼠标时它位于按钮 1 和按钮 2 上。似乎事件处理程序已在队列中注册,但单击发生的元素已确定稍后需要处理 click 事件并触发已注册的事件处理程序。 对我来说,这种行为比在点击时根据 DOM 的状态确定被点击的元素更有意义,并且是一种更可预测的行为。 但我仍然不确定我的示例中的行为是否始终得到保证。

const button2 = getButton(2);
const button3 = getButton(3);

const removeButton2 = () => button2.parentElement.removeChild(button2);

button2.addEventListener("click", () => console.log("button 2 clicked"));

button3.addEventListener("click", () => console.log("button 3 clicked"));

button1.addEventListener("click", () => {
  console.log("button 1 clicked");

  const fragment = document.createDocumentFragment();
  for (let i = 0; i < 70_000; i++) {
    const a = document.createElement("a");
    a.innerHTML = "text " + i;
    fragment.appendChild(a);
  }

  document.documentElement.appendChild(fragment);
  removeButton2();
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button id="button-1">button 1</button>
    <button id="button-2">button 2</button>
    <button id="button-3">button 3</button>
  </body>
</html>

我知道这种现实世界的场景不太可能在浏览器的当前状态下偶然发生,在这种状态下一切都发生得如此之快,但希望能获得更多关于该主题的光线和资源。

这将取决于实现,即使所有现代 UA 都公开相同的行为。 例如,在旧的 IE 中,它对所有内容都使用单个进程,您的点击事件在被阻止时将被忽略。

现代浏览器现在有许多辅助进程,因此它们可以处理它(浏览器进程可以保留消息,直到渲染器准备好处理它)。
所以是的,在当前的主流浏览器中,只有当第一个回调完成时,渲染器才会处理您的事件,这就是实际的 DOM 事件将被构造的时候,因此它将使用更新的 DOM 树。

您可以看到这个 Chromium 设计文档,其中谈到了一点: https ://www.chromium.org/developers/design-documents/displaying-a-web-page-in-chrome/#life-of-a-mouse -click-message ,这是关于 IPC 消息传递的一般信息: https ://www.chromium.org/developers/design-documents/inter-process-communication/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM