javascript/browser: 事件调度具体发生在什么时候?
javascript/browser: when does event dispatching exactly happen?
此 SO question & answers and DOM level3 docs 说明 手动 事件在浏览器中 同步 调度。但是,我的问题涉及与用户相关的事件(实际点击),而不是手动触发的事件。
我创建了一个带有按钮 + onclick 处理程序的 small jsfiddle demo,该处理程序执行一些同步工作 2 秒(阻塞同步等待,足够长的时间让我的眼睛看到发生了什么)。打开控制台查看 console.log
s.
测试。我在按钮上点击了几次。虽然第一次点击(及其同步处理)使按钮被按下(看起来像被禁用),但其他点击也会被存储并稍后通过事件循环异步处理。
问题是:
- 事件调度具体发生在什么时候?用户事件(例如点击)是立即推送到 JS 消息队列还是有一个中间 Web API 队列...或者换句话说 - 这个事件调度与哪个队列相关?
- 大多数事件(
click
、blur
等 - 除了 load
)在用户事件(非手动事件)的情况下同步处理是什么意思?考虑到上面的测试,第一次点击会执行同步阻塞回调(我希望在此期间不会发生任何其他事情),无论如何,下一次点击都会存储在队列中。所以存储事件无论如何都是并行的(必须是,因为主 javascirpt 线程很忙)。从理论上讲,如果事件是异步处理的,会有什么不同吗?
slightly modified demo 显示对于给定的点击事件,事件冒泡并调用所有相关的事件处理程序,就像事件冒泡被阻塞一样,直到发生其他任何事情(本例中为超时)。但是仍然不清楚为什么事件调度是同步的。
在真实事件的上下文中谈论同步毫无意义,因为事件队列仅在当前执行堆栈已清空时才处理,即当有不再需要执行同步代码。这使得相关的事件处理程序 异步 。您在 fiddle.
中提供的点击事件处理程序也是如此
运行ning 代码在 运行s 时阻止任何其他操作并不表明该代码是如何触发的:异步或同步。在这两种情况下,一个 2 秒的繁忙循环将阻塞 2 秒。当我们异步说代码 运行s 时,它只说明代码被调用的 how/when,而不是它如何 运行s。同步和异步代码 运行 都以阻塞的方式出现。这有一些例外——例如 web workers 运行 在他们自己的线程中。
这些“真实”事件被推送到 JS 消息队列中。当然,它们首先从 OS 事件队列中消耗,但这是特定于实现的。重要的是它们最终出现在 JS 消息队列中,连同它们的处理程序。 JavaScript 引擎仅在先前 运行ning 代码 ran to completion 时处理事件。因此,这些事件处理程序被异步调用。
如果是“手动”事件,即由 jQuery 的 .trigger()
方法等代码触发的事件,区分异步和同步是有意义的。在异步情况下,事件将被放入 JS 队列,当前代码将首先 运行 完成。在同步情况下,事件不会被放入 JS 队列,而是像函数调用一样执行。因此,事件的处理作为对调用堆栈的附加调用发生,之后您的代码将恢复,就像在正常函数调用的 return 之后一样:这是同步行为。
这里忽略了micro tasks的概念,只是说异步代码的执行有不同的优先级。
您指的是 JavaScript 事件循环。
回答您关于为什么分派(也称为处理消息队列外的项目)同步发生的问题:JavaScript 是单线程的,因此不可能同时处理 2 条消息时间.
关于 JS 事件循环的一些额外信息:
In web browsers, messages are added any time an event occurs and there
is an event listener attached to it. If there is no listener, the
event is lost. So a click on an element with a click event handler
will add a message--likewise with any other event.
取自https://developer.mozilla.org/nl/docs/Web/JavaScript/EventLoop
这里有一个不同的观点,取自
http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/:
JavaScript runtimes contain a message queue which stores a list of
messages to be processed and their associated callback functions.
These messages are queued in response to external events (such as a
mouse being clicked or receiving the response to an HTTP request)
given a callback function has been provided. If, for example a user
were to click a button and no callback function was provided – no
message would have been enqueued.
下面是关于同步处理消息队列项目的部分:
In a loop, the queue is polled for the next message (each poll
referred to as a “tick”) and when a message is encountered, the
callback for that message is executed.
最后:
Would there be any difference, theoretically, it events were processed asynchronously?
完全正确。如果您期望三个队列的消息在某处记录 1
、2
和 3
,它可能会以备用顺序记录序列,例如 2
、1
, 3
.
此 SO question & answers and DOM level3 docs 说明 手动 事件在浏览器中 同步 调度。但是,我的问题涉及与用户相关的事件(实际点击),而不是手动触发的事件。
我创建了一个带有按钮 + onclick 处理程序的 small jsfiddle demo,该处理程序执行一些同步工作 2 秒(阻塞同步等待,足够长的时间让我的眼睛看到发生了什么)。打开控制台查看 console.log
s.
测试。我在按钮上点击了几次。虽然第一次点击(及其同步处理)使按钮被按下(看起来像被禁用),但其他点击也会被存储并稍后通过事件循环异步处理。
问题是:
- 事件调度具体发生在什么时候?用户事件(例如点击)是立即推送到 JS 消息队列还是有一个中间 Web API 队列...或者换句话说 - 这个事件调度与哪个队列相关?
- 大多数事件(
click
、blur
等 - 除了load
)在用户事件(非手动事件)的情况下同步处理是什么意思?考虑到上面的测试,第一次点击会执行同步阻塞回调(我希望在此期间不会发生任何其他事情),无论如何,下一次点击都会存储在队列中。所以存储事件无论如何都是并行的(必须是,因为主 javascirpt 线程很忙)。从理论上讲,如果事件是异步处理的,会有什么不同吗?
slightly modified demo 显示对于给定的点击事件,事件冒泡并调用所有相关的事件处理程序,就像事件冒泡被阻塞一样,直到发生其他任何事情(本例中为超时)。但是仍然不清楚为什么事件调度是同步的。
在真实事件的上下文中谈论同步毫无意义,因为事件队列仅在当前执行堆栈已清空时才处理,即当有不再需要执行同步代码。这使得相关的事件处理程序 异步 。您在 fiddle.
中提供的点击事件处理程序也是如此运行ning 代码在 运行s 时阻止任何其他操作并不表明该代码是如何触发的:异步或同步。在这两种情况下,一个 2 秒的繁忙循环将阻塞 2 秒。当我们异步说代码 运行s 时,它只说明代码被调用的 how/when,而不是它如何 运行s。同步和异步代码 运行 都以阻塞的方式出现。这有一些例外——例如 web workers 运行 在他们自己的线程中。
这些“真实”事件被推送到 JS 消息队列中。当然,它们首先从 OS 事件队列中消耗,但这是特定于实现的。重要的是它们最终出现在 JS 消息队列中,连同它们的处理程序。 JavaScript 引擎仅在先前 运行ning 代码 ran to completion 时处理事件。因此,这些事件处理程序被异步调用。
如果是“手动”事件,即由 jQuery 的 .trigger()
方法等代码触发的事件,区分异步和同步是有意义的。在异步情况下,事件将被放入 JS 队列,当前代码将首先 运行 完成。在同步情况下,事件不会被放入 JS 队列,而是像函数调用一样执行。因此,事件的处理作为对调用堆栈的附加调用发生,之后您的代码将恢复,就像在正常函数调用的 return 之后一样:这是同步行为。
这里忽略了micro tasks的概念,只是说异步代码的执行有不同的优先级。
您指的是 JavaScript 事件循环。
回答您关于为什么分派(也称为处理消息队列外的项目)同步发生的问题:JavaScript 是单线程的,因此不可能同时处理 2 条消息时间.
关于 JS 事件循环的一些额外信息:
In web browsers, messages are added any time an event occurs and there is an event listener attached to it. If there is no listener, the event is lost. So a click on an element with a click event handler will add a message--likewise with any other event.
取自https://developer.mozilla.org/nl/docs/Web/JavaScript/EventLoop
这里有一个不同的观点,取自
http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/:
JavaScript runtimes contain a message queue which stores a list of messages to be processed and their associated callback functions. These messages are queued in response to external events (such as a mouse being clicked or receiving the response to an HTTP request) given a callback function has been provided. If, for example a user were to click a button and no callback function was provided – no message would have been enqueued.
下面是关于同步处理消息队列项目的部分:
In a loop, the queue is polled for the next message (each poll referred to as a “tick”) and when a message is encountered, the callback for that message is executed.
最后:
Would there be any difference, theoretically, it events were processed asynchronously?
完全正确。如果您期望三个队列的消息在某处记录 1
、2
和 3
,它可能会以备用顺序记录序列,例如 2
、1
, 3
.