【发布时间】:2023-04-03 18:16:01
【问题描述】:
我的页面上运行了一段 JavaScript 代码;我们称之为func1。运行需要几毫秒。当该代码运行时,用户可以单击、移动鼠标、输入一些键盘输入等。我还有另一个代码块func2,我想在所有这些排队的输入事件都解决后运行它。也就是我要保证顺序:
func1- 绑定到
func1运行时发生的输入事件的所有处理程序 func2
我的问题是:在func1 的末尾调用setTimeout func2, 0 是否足以保证在所有现代浏览器中的这种排序? 如果该行出现在func1 的开头怎么办?在这种情况下,我应该期待什么顺序?
请参考相关规范或测试用例来备份您的答案。
更新:事实证明,不,这还不够。我在最初的问题中没有意识到的是,在执行当前代码块之前,输入事件甚至都没有添加到队列中。所以如果我写
// time-consuming loop...
setTimeout func2, 0
那么只有在运行setTimeout 之后 才会将在耗时循环期间发生的任何输入事件(点击等)排队。 (为了测试这一点,请注意,如果您在耗时的循环之后立即删除 onclick 回调,那么在循环期间发生的点击不会触发该回调。)所以@ 987654337@ 先排队,优先。
设置1 的超时似乎可以解决 Chrome 和 Safari 中的问题,但在 Firefox 中,我看到输入事件在超时后解决了高达 80 (!)。因此,纯粹基于时间的方法显然不会达到我想要的效果。
简单地将一个setTimeout ... 0 包裹在另一个内部也是不够的。 (我希望第一个超时会在输入事件排队后触发,第二个超时会在它们解决后触发。没有这样的运气。)添加第三层或第四层嵌套也不够(参见下面的更新 2 )。
因此,如果有人有办法实现我所描述的(除了设置 90+ 毫秒的超时),我将不胜感激。或者这对于当前的 JavaScript 事件模型来说根本不可能?
这是我最新的 JSFiddle 测试平台:http://jsfiddle.net/EJNSu/7/
更新 2: 部分解决方法是将 func2 嵌套在两个超时内,在第一个超时内删除所有输入事件处理程序。但是,这有一个不幸的副作用,即导致func1 期间发生的一些甚至全部输入事件无法解决。 (前往http://jsfiddle.net/EJNSu/10/ 并尝试快速单击链接几次以观察此行为。警报告诉您点击了多少次?)所以这再次让我感到惊讶;我认为调用setTimeout func2, 0(其中func2 将onclick 设置为null)不会阻止响应一整秒前发生的点击而运行该回调。我想确保所有输入事件都会触发,但我的函数会在它们之后触发。
更新 3:我在玩过这个测试台后在下面发布了我的答案,这很有启发性:http://jsfiddle.net/TrevorBurnham/uJxQB/
将鼠标移到方框上(触发 1 秒的阻塞循环),然后单击多次。在循环之后,您执行的所有点击都会播放:顶部框的 click 处理程序将其翻转到另一个框下方,然后接收下一个 click,依此类推。 mouseenter 回调中触发的超时不会始终发生在点击事件之后,即使在相同的硬件和操作系统上,点击事件发生所需的时间也因浏览器而异。 (这个实验出现的另一个奇怪的事情是:即使我将鼠标稳定地移入框内,我有时也会收到多个 jQuery mouseenter 事件。不确定那里发生了什么。)
【问题讨论】:
-
我认为您的情况不能保证订单。我还没有听说过事件处理优先级。如果您喜欢的情况很明显,我认为您应该在执行 setTimeout 之前处理一个事件队列。您是否在 google 中搜索过:“javascript 事件队列”?
-
例如,对于 Opera:dev.opera.com/articles/view/…
-
@sergzach 但是我将如何“在执行
setTimeout之前处理事件队列”?据我所知,没有办法从onclick回调等中询问“在此之后是否还有其他 DOM 事件要触发?” -
Opera 文章强烈建议我回答我的问题是“是”,但我希望看到更权威的东西。
-
@jessegavin 这是一个测试用例:gist.github.com/1038695
标签: javascript dom input dom-events