此SO question & answers和DOM level3 docs表示在浏览器中手动事件同步。然而,我的问题涉及用户相关事件(真实点击),而不是手动触发事件。
我使用按钮+ onclick处理程序创建了一个small jsfiddle demo,处理程序执行了一些同步工作2秒(阻止同步等待,足够长的时间让我的眼睛看看发生了什么)。打开控制台以查看console.log
s。
测试。我点击按钮几次。虽然第一次单击(及其同步处理)使按钮按下(看起来像禁用),但其他点击也会被存储,然后通过事件循环异步处理。
问题是:
click
,blur
等 - 除load
之外的其他事件 - 同步处理是什么意思?鉴于上面的测试,第一次单击使得同步阻塞回调被执行(我希望在此期间不会发生任何其他事情),并且无论如何,下一次点击存储在队列中。所以存储事件无论如何都是平行的(必须是,因为主javascirpt线程很忙)。从理论上讲,它是否会有异步处理?slightly modified demo表明,对于给定的单击事件,事件会冒泡并调用所有相关的事件处理程序,就像事件冒泡被阻塞一样,直到其他任何事情(本例中为超时)都可能发生。但仍然不清楚为什么事件调度是同步的。
答案 0 :(得分:1)
在实际事件的上下文中谈论 synchronous 是没有意义的,因为事件队列仅在当前执行堆栈被清空时处理,即当没有更多的同步代码时执行。这使得相关事件处理程序异步。对于您在小提琴中提供的单击事件处理程序也是如此。
正在运行的代码在运行时阻止任何其他操作并不表示该代码是如何触发的:异步或同步。在这两种情况下,2秒的繁忙循环将被阻塞2秒。当我们说代码以异步方式运行时,它只会说明调用代码的方式/时间,而不是代码的运行方式。同步和异步代码都以阻塞的方式运行。这有一些例外 - 例如web workers在他们自己的线程中运行。
这些“真实”事件被推送到JS消息队列中。当然,它们首先从OS事件队列中消耗,但这个实现是特定的。重要的是它们最终在JS消息队列中,并与它们的处理程序一起。 JavaScript引擎仅在先前运行的代码ran to completion时处理事件。结果,这些事件处理程序被异步调用。
在“手动”事件的情况下,即由jQuery的.trigger()
方法等代码触发的事件,在异步和同步之间存在差异。在异步情况下,事件将放在JS队列中,当前代码将首先运行完成。在同步情况下,事件不会放在JS队列中,而是像函数调用一样执行。因此,事件的处理作为调用堆栈上的附加调用发生,之后您的代码将恢复,就像从正常函数调用返回之后:这是同步行为。
我忽略了micro tasks的概念,这意味着执行异步代码有不同的优先级。
答案 1 :(得分:0)
您指的是JavaScript事件循环。
回答你的问题,为什么调度(也称为消息队列中的处理项)同步发生:JavaScript是单线程的,所以2条消息无法在同一时间处理。
有关JS事件循环的一些额外信息:
在Web浏览器中,只要事件发生,就会添加消息 是附加到它的事件监听器。如果没有听众,那么 事件丢失了。因此,单击具有单击事件处理程序的元素 将添加一条消息 - 与任何其他事件一样。
取自https://developer.mozilla.org/nl/docs/Web/JavaScript/EventLoop
这是一个不同的看法,取自
http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/:
JavaScript运行时包含一个存储列表的消息队列 要处理的消息及其关联的回调函数。 这些消息排队以响应外部事件(例如a 单击鼠标或接收对HTTP请求的响应) 给定了回调函数。例如,如果是用户 是单击一个按钮,没有提供回调功能 - 没有 消息会被排队。
这是关于消息队列中同步处理项的部分:
在循环中,轮询队列以查找下一条消息(每次轮询 被称为“tick”)并且当遇到消息时, 执行该消息的回调。
最后:
理论上会不会有异步处理事件?
共。如果您希望三个队列消息在某处记录1
,2
和3
,则可能会以备用顺序记录序列,例如2
,{{ 1}},1
。