竞争条件与JavaScript事件处理

Race conditions with JavaScript event handling?

本文关键字:事件处理 JavaScript 条件 竞争      更新时间:2023-09-26

我们知道JavaScript是单线程的,但是我们想确认一下我们对JavaScript中异步事件处理的理解。更重要的是,我们要确认我们没有暴露在潜在的竞争条件下。

从概念上讲,我们的移动应用程序是这样工作的:
  1. 我们在加载移动页面时调用foo函数

  2. foo结束时,如果计数器大于0,我们使用setTimeout再次调用foo(延迟1秒)。如果计数器到达0,我们加载一个新页面。超时保存在一个变量中

  3. 如果按钮被点击,我们调用do_tap函数并清除在步骤2中保存的超时变量(并做其他事情)。

do_tapfoo都更新了相同的页面元素,我们想确认它们不会相互踩到。

问题:

  1. 假设在foo执行过程中发生轻拍。浏览器队列do_tap会在foo完成后开始执行吗?换句话说,我们能保证一旦foo启动,我们永远不会看到foodo_tap的执行交错吗?

  2. 如果tap先发生怎么办?do_tap保证在foo开始之前完成,对吗?

除了web worker和协作框架或窗口(这里没有使用),Javascript在给定窗口内是单线程的,因此在该窗口中永远不会同时运行两个执行线程。因此,您永远不必担心竞争条件,这可能是使用线程时常见的问题。

在幕后,Javascript有一个事件队列。当前执行的线程将运行到完成,然后当它完成时,javascript解释器将检查事件队列,看看是否还有更多的事情要做。如果是,则触发该事件并启动另一个执行线程。几乎所有事情都要经过这个事件队列(计时器、按键事件、调整大小事件、鼠标事件等)。

你可以在我关于这个主题的另一个答案中阅读更多相关的参考资料。

事件继续单线程执行,直到事件被处理。在此之前,不会启动其他事件循环。

换句话说,当一个处理程序正在为某个事件运行时,其他任何事件的处理程序都不会中断它。

因此问题1和问题2的答案都是"是"。(当然,这是排除浏览器漏洞,但如果你考虑到这一点,你就不能走得太远。这并不是说有什么同步原语可以依赖。我这么说只是因为在运行另一个"DOMready"事件处理程序的过程中,有一段时间Safari可能会触发一个"DOMready"事件。然而,这显然是一个bug。)

只要Do_tap()所做的第一件事是clearartimeout,那么在Do_tap()执行期间就没有机会运行foo。然而,如果在foo()中启动了一个异步进程,这样一个数据库请求,那么在foo()完成它的请求时,可能会有一个潜在的等待来访问Do_tap()中的数据库,如果foo()有一个回调函数,理论上可以在Do_tap()完成执行后调用。

我没有听到其他人这么说,但我认为第2点的答案是,不同的浏览器实现在首先处理哪个队列事件方面可能而且确实存在细微的差异。不,没有交错的可能性,但是语言规范不能保证首先处理setTimeout(func, 0)或鼠标事件,在实践中可能很重要。而setTimeout(func, 100) 保证在当前处理事件期间接收到的挂起事件之后处理。

只是说。