JavaScript 事件处理的竞争条件?
Posted
技术标签:
【中文标题】JavaScript 事件处理的竞争条件?【英文标题】:Race conditions with JavaScript event handling? 【发布时间】:2012-01-26 12:34:07 【问题描述】:我们了解 javascript 是单线程的,但我们想确认我们对 JavaScript 中的异步事件处理的理解。更重要的是,我们想确认我们没有面临潜在的竞争条件。
从概念上讲,我们的移动应用程序是这样工作的:
我们在加载移动页面时调用函数foo
。
在foo
的末尾,如果计数器大于0
,我们使用setTimeout
再次调用foo
(延迟一秒)。如果计数器命中0
,我们会加载一个新页面。超时保存在一个变量中。
如果点击按钮,我们调用函数do_tap
并清除第二步中保存的超时变量(并执行其他操作)。
do_tap
和 foo
都更新了同一个页面元素,我们想确认它们不会互相踩踏。
问题:
假设在foo
的执行过程中发生了点击。浏览器队列do_tap
会在foo
完成后开始执行吗?换句话说,我们是否保证一旦foo
启动,我们就永远看不到foo
和do_tap
交错执行?
如果先点击怎么办? do_tap
保证在 foo
开始之前完成,对吧?
【问题讨论】:
由于执行是单线程的,foo
根本不可能在返回Do_tap
之前开始执行(反之亦然)。阅读这篇文章,您将了解浏览器中的执行队列是如何工作的:ejohn.org/blog/how-javascript-timers-work
【参考方案1】:
除了网络工作者和协作框架或窗口(此处未使用)外,Javascript 在给定窗口中是单线程的,因此在该窗口中永远不会有两个执行线程同时运行。因此,您不必担心在使用线程时可能是典型的竞争条件。
在幕后,Javascript 有一个事件队列。您当前的执行线程将运行到完成,然后当它完成时,javascript 解释器将检查事件队列以查看是否还有更多事情要做。如果是这样,它会触发该事件并启动另一个执行线程。几乎所有事情都经过该事件队列(计时器、按键事件、调整大小事件、鼠标事件等...)。
您可以在my other answers 之一中阅读有关此主题的更多信息并查看大量相关参考资料。
【讨论】:
这几乎是真的,除了帧有不同的执行上下文,如果它们都访问相同的数据,比如top.myVariable
,你可能会有竞争条件。请参阅dev.opera.com/articles/view/… 并在该页面中搜索种族
我还想提一下 Chrome 扩展,您可以在其中拥有多个单独的执行上下文。我没有发现竞争条件经常发生,很大程度上取决于您正在构建的内容,但确实会发生。【参考方案2】:
事件执行单线程进行,直到事件被处理。在此之前,不会启动其他事件循环。
换句话说,当某个事件的处理程序正在运行时,任何其他事件的其他处理程序都不会中断它。
因此,问题 1 和问题 2 的答案都是“是”。 (当然,这是排除浏览器错误,但如果你考虑到这一点,你就不会走得太远。这不像是有任何同步原语可以依靠。我这么说只是因为有一段时间在此期间,Safari 可能会在运行另一个“DOMready”事件处理程序的过程中触发“DOMready”事件。然而,这显然是一个错误。)
【讨论】:
谢谢,我们只是想确认一下! do_tap() 和 foo() 都更新同一个页面元素,我们希望确保它们不会互相踩踏。再次感谢您的肯定。【参考方案3】:只要 Do_tap() 做的第一件事是 clearTimeout,在 Do_tap() 执行期间 foo 就没有机会运行。但是,如果在 foo() 中启动了这样一个数据库请求的异步进程,那么当 foo() 完成其请求时,可能会在 Do_tap() 中等待访问数据库,并且如果 foo() 有一个回调函数可以理论上在 Do_tap() 执行完成后调用。
【讨论】:
【参考方案4】:我没有听到其他人这么说,但我认为#2 的答案是,不同的浏览器实现可以并且确实以微妙的方式不同,即首先处理哪些排队事件。不,没有交错的可能性,但是语言规范不能保证首先处理 setTimeout(func, 0) 还是鼠标事件,实际上可能很重要。而 setTimeout(func, 100) 是保证在当前处理的事件期间接收到的挂起事件之后处理。
只是说。
【讨论】:
以上是关于JavaScript 事件处理的竞争条件?的主要内容,如果未能解决你的问题,请参考以下文章
前端—— JavaScript基础操作:if语句for循环while循环for...infor...of异常处理函数事件JS选择器JS操作页面样式