【问题标题】:Execution of browser default actions of simulated DOM events模拟DOM事件的浏览器默认动作的执行
【发布时间】:2013-12-13 03:02:34
【问题描述】:

我有一些代码通过 DOM API(createEvent、initEvent、dispatchEvent 等)触发/模拟 DOM 事件。对于大多数 DOM 事件(例如单击),有一个浏览器默认操作,例如跟随链接。

由于 JavaScript 代码执行是单线程的,我不确定当我的代码批量触发多个事件时执行流程如何。所以假设我这样做(伪代码):

for (var i = 0; i < 10; i++) {
  var event = document.body.createEvent('MouseEvent');
  event.initMouseEvent(...);
  document.body.dispatchEvent(event); 
}

会发生什么?我的循环是否首先完全执行,然后处理所有事件,导致默认浏览器操作触发并注册事件侦听器执行?还是每次调用dispatchEvent触发默认动作(和事件监听器)时代码执行中断?

谢谢

【问题讨论】:

  • 事件在 javascript 中被阻塞。每次迭代都会阻塞触发事件,然后继续循环
  • 这是否意味着浏览器默认动作也会立即执行?

标签: javascript events dom


【解决方案1】:

因为 JS 不是多线程的,所以每次调度事件时都会立即触发 - 实现不会创建一些事件队列以在下一个周期触发。

这是旧的mutation events 已被弃用的原因之一。例如,如果您向一个节点添加 400 个元素,它将触发 400 个突变事件(传播),从而减慢几乎所有内容。

因此,在您的代码 sn-p 中,循环的每次迭代都会创建鼠标事件、调度鼠标事件、处理鼠标事件的所有侦听器,然后继续执行循环的下一次迭代。

【讨论】:

  • 感谢您的解释。我创建了一个代码示例,您可以在其中看到您解释的内容。但是我更关心浏览器的默认操作。您可以在这里看到jsbin.com/AGUCuMAf/2/edit?html,js,console,output,只有在调度所有 100 个事件之后,浏览器才会真正跳转到该锚点。但是,由于它已经在每次调度事件时执行所有关联的侦听器,我希望它立即跟随锚点。
  • 我相信这是浏览器在运行循环时“挂起”的结果。循环需要很长时间才能完成,由于 js 只有一个堆栈,DOM 更新只会在下一个循环发生,除非你有一些明确的代码来启动回流。
  • 实际上该示例无法正常工作。我现在正在尝试修复它。但你提到的是我最初所说的。只有一个线程用于代码执行(在这种情况下是 for 循环和所有潜在的事件侦听器)和浏览器 GUI(浏览器默认操作,在示例中为跳转到锚点)。如果立即触发事件并且附加的侦听器也立即执行,那么使用浏览器默认操作等待 for 循环完成会有点奇怪,不是吗?
  • 浏览器(默认)操作在每个循环中被调用,但是直到线程有时间它才会真正运行(参见setImmediatesetTimeout(fn, 0))。我认为 DOM 在处理完您的代码后会尝试更新视图(即滚动到#below)。
  • 对不起,我认为你明白了要点;我相信发生的事情是,当点击事件被触发时,浏览器会为该事件注册默认处理程序,即单击元素,但实际上它会将大部分工作推迟到浏览器“有时间”,即超时
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 2011-08-28
  • 2011-04-01
  • 1970-01-01
  • 2020-05-05
  • 2014-08-10
相关资源
最近更新 更多