6

所以我最近回答了一个问题,OP 问我是否可以在我的答案中添加以下关于 DOM 事件的内容:

也许您还可以添加到您的答案中,不仅它们首先执行,而且后续事件被阻止,直到第一个事件完成。

好吧,我可以添加吗?我是否知道使用 DOM 事件将一次运行一个事件,并在下一个事件开始之前等待前一个事件完成?

我至少知道浏览器 JavaScript 总是这样吗?

到目前为止,要找到一个确凿的答案非常困难,我本以为“是”,但我就是找不到。


澄清:我不是要在处理程序中添加其他异步处理程序,或者调用 setTimeout 或工作人员等。我要问的是是否保证事件处理程序执行的顺序,并且下一个开始仅前一个完成执行?一个好的答案会引用一个可靠的来源(最好是一个规范)。这里没有关于线程的内容。

4

2 回答 2

7

是也不是,所有的 JS 都在同一个线程上运行,除了 web worker,它们不能访问 DOM。http://dev.opera.com/articles/view/timing-and-synchronization-in-javascript/

这是该页面上的一些相关信息

所有事件处理函数都按顺序执行,并且在处理下一个事件之前,每个事件都被完全处理(包括通过 DOM 冒泡和执行默认操作)。

但是,稍后在该页面上,他们提到

比赛条件

每个窗口(和框架)都有自己的事件队列。在 Opera 中,每个窗口都有自己的 JavaScript 线程。这包括 iframe 中的窗口。结果是从不同帧启动的事件处理程序可能同时执行。如果这些同步脚本修改了共享数据(如顶部窗口中的属性),我们就有可能出现竞争条件。

事件都被放入一个事件队列中,所有事件处理都发生在同一个线程中。连同所有异步回调,如 XHR 和setTimeout.

还要注意嵌套事件,因为如果您触发一个事件,许多方法将执行并且它们可能会更改全局状态。示例http://jsfiddle.net/rpxZ4/

$('#d1').click(function(){
    alert('before ');
    $('#d2').trigger('click');
    $('#d3').trigger('click'); 
    alert('after ');
});

$('#d2, #d3').click(function() {
    alert('clicked ' +this.id);
});

以下是 Opera 处理时间的建议

  • 不要有长时间运行的脚本。
  • 不要使用同步 XMLHttpRequests。
  • 不要让从不同框架启动的脚本操纵相同的全局状态。
  • 不要使用警告框进行调试,因为它们可能会完全改变程序的逻辑。
于 2013-09-16T21:39:48.670 回答
1

好吧,这实际上取决于您在处理程序中做什么以及如何定义第一个处理程序结束时刻?

例如,如果您只在 eventHandler1 中执行同步操作,那么您确定 eventHandler2 在 eventHandler1 完成之前不会被触发。原因是javascript是单线程的。

但是,想象一下这样的场景:点击 button1 会触发 eventHandler1,它实际上会发出 ajax 请求。在那种情况下,您实际上认为什么是“eventHandler1 的结束”?如果是 ajax 请求返回的那一刻,那么 eventHandler2 肯定会在 eventHandler1 完成之前开始(并且可能结束)执行。

简而言之:每当您执行仅同步操作时,都会保证顺序。

从评论中添加:

http://www.w3.org/TR/DOM-Level-3-Events/#sync-async例如,它说:“这个虚拟队列中的每个事件都必须延迟,直到前一个事件完成其传播行为,或被取消。”


好吧,现在我们回到“我们在谈论什么类型的事件”这个问题?如前所述:如果它是异步事件,则确保不能保证顺序。但最初的困境是关于点击事件,而那个不是异步的,而是同步的。对于同步事件文档明确指出:必须将同步事件(“同步事件”)视为它们在先进先出模型中的虚拟队列中,按时间发生顺序排序,关于其他事件、DOM 中的更改以及用户交互。


是的,没有保证。现在添加 javascript 是单线程的,你不能让它们同时执行。但是,是的,严格来说 DOM - 无法保证之前会发生哪一个。


再加一条评论……您可能拥有完全相同的 DOM,但可以从 Java 多线程环境中访问。然后呢?:) 那么您必须实现自己的线程安全异步事件处理,因为您不再像使用 javascript 那样受到单线程环境的“保护”。所以,我看到的结论是 DOM 规范确实要求同步事件是 fifo 实现的。异步事件的执行取决于堆栈/线程实现。在 Javascript 中,这意味着 2 个处理程序不能重叠,但在 Java 中,例如不一定意味着。

于 2013-09-16T16:27:58.177 回答