JS 处理与监听器并行发生的事件
我不确定某些 JS 代码运行时如何生成事件。
例如,在这种情况下:
<div id="div1"> text </div>
<div id="div2"> text </div>
div2.onpointermove = (e) => {
console.log("old handler");
};
div1.onpointerdown = (e) => {
div2.onpointermove = (e) => {
console.log("new handler");
}; };
布局:
+-----+-----+
|div1 | div2|
+-----+-----+
场景:
- 指针在
div1
的边缘像素上向下 - 指针移动到
div1
之外并进入div2
当 JS 代码运行时在单线程上,用户可以平行移动鼠标来运行一些JS代码。我想知道,当一些JS代码运行时,事件是如何生成并处理的?
可能的时间线:
A)
- 指针向下放在
div1
的边缘像素上, - 将鼠标移动到与事件侦听器 JS 代码并行运行的
div2
上 - ,同时 JS 代码处理事件侦听器,鼠标事件排队
- 调用
div1.onpointerdown
- 添加新处理程序
div2.onpointermove
- 排队的鼠标事件使用new处理强> 听众集
- “new handler”打印在控制台上
B)
- 指针向下放在
div1
的边缘像素上 - 将鼠标移动到与事件侦听器 JS 代码并行的
div2
上, - 同时 JS 运行代码处理事件监听器,鼠标事件被忽略
- 调用
div1.onpointerdown
- 添加新处理程序
div2.onpointermove
- 开始再次注册事件
- 指针移动在
div2
丢失,控制台没有打印任何内容(如果div1.onpointerdown
处理完后鼠标没有移动,并且JS没有比较前后鼠标位置处理代码块)
C)
- 将指针向下放在
div1
的边缘像素上 - 将鼠标移动到与事件侦听器平行的
div2
上 JS 代码 - 在 JS 代码处理时 运行事件监听器,鼠标事件是排队要使用当前的旧事件侦听器集进行处理
- 调用
div1.onpointerdown
- 添加新处理程序
div2.onpointermove
- 使用旧处理队列中的下一个事件,记录的事件侦听器
- “旧处理程序”打印在控制台上
我不知道,会发生哪种情况,或者是否依赖于浏览器?
pointerdown
、pointermove
仅用于示例目的,我对这些确切事件的怪癖不感兴趣,而是对如何生成事件的更一般概念感兴趣/在某些 JS 代码运行时保存/忽略/处理,这会为与代码块运行并行发生的事件添加事件处理程序。
另外,是否存在通用行为,或者是否存在特定于实现的细节?
I am not sure, how events are generated while some JS code is running.
For example in this scenario:
<div id="div1"> text </div>
<div id="div2"> text </div>
div2.onpointermove = (e) => {
console.log("old handler");
};
div1.onpointerdown = (e) => {
div2.onpointermove = (e) => {
console.log("new handler");
}; };
Layout:
+-----+-----+
|div1 | div2|
+-----+-----+
Scenario:
- pointerdown on an edge pixel of
div1
- pointermove outside of
div1
and intodiv2
While the JS code runs on a single thread, the user can move the mouse parallel to some JS code running. I would like to know, how events are generated and then processes, while some JS code is running?
Possible timelines:
A)
- pointer down on the edge-pixel of
div1
- move the mouse onto
div2
parallel to the event listener JS code running - while the JS code processes the event listeners, the mouse events are queued
- invoke
div1.onpointerdown
- add new handler
div2.onpointermove
- the queued mouse events are processed with the new set of listeners
- "new handler" is printed on the console
B)
- pointer down on the edge-pixel of
div1
- move the mouse onto
div2
parallel to the event listener JS code running - while the JS code processes the event listeners, the mouse events are ingored
- invoke
div1.onpointerdown
- add new handler
div2.onpointermove
- start to register events again
- the pointer move on
div2
was lost, nothing is printed on the console (if the mouse did not move afterdiv1.onpointerdown
has finished processing, and JS did not compare the mouse position before-after processing the code-chunk)
C)
- pointer down on the edge-pixel of a
div1
- move the mouse onto
div2
parallel to the event listener JS code running - while the JS code processes the event listeners, the mouse events are queued to be processed with the current, old set of event listeners
- invoke
div1.onpointerdown
- add new handler
div2.onpointermove
- process the next event from the queue with the old, recorded event listeners
- "old handler" is printed on the console
I don't know, which scenario will happen, or if it is browser-dependent?
The pointerdown
, pointermove
is only for the purpose of the example, I am not interested in the quirks of those exact events, rather the more general concept of how events are generated/saved/ignored/handled while some JS code is running which is adding event handlers for those event happening parallel to the code chunk running.
Also, if there is universal behavior, or there are implementation-specific details?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一般来说,使用方法 A - 事件排队,然后在 JS 事件循环完成先前处理程序的执行后进行处理。
然而,快速且连续(不离散)的事件,如滚动或鼠标移动(而不是点击或按键)可以被引擎限制,这样,如果 JS 代码处理它们需要很长时间,它就会触发更少的事件。这可能相当于丢弃一些事件(方法 B)——但是你怎么知道呢?
至于方法C,则不使用。排队的是事件,而不是运行注册处理程序的任务。这在删除事件侦听器时尤其重要 - 在调用
removeEventListener
后,您可以确定不会再次调用它,即使触发该事件的事件仍在排队中也是如此。然而,对于安装新的事件侦听器,并没有真正的方法来区分 - 代码无法判断事件是在安装侦听器之前还是之后触发的,因此这为浏览器提供了一些优化的余地。In general, approach A is used - events are queued, then processed once the JS event loop has finished execution of previous handlers.
However, fast and continuous (indiscrete) events like scrolling or mouse movement (as opposed to, say clicks or keypresses) can be throttled by the engine, so that it fires fewer of them if the JS code processing them takes a long time. This may amount to discarding some events (approach B) - but how you can you tell?
As for approach C, that is not used. It's the events that are queued, not the tasks to run the registered handlers. This is especially important when removing event listeners - after you call
removeEventListener
, you can be certain that it won't be called again, even if an event is still queued that would have triggered it. However, for installing new event listeners there's not really a way to tell the difference - the code cannot tell whether the event was fired before or after the listener was installed, so this gives browsers some leeway to optimise.