我们理解JavaScript是单线程的,但我们想要确认我们对JavaScript中异步事件处理的理解。更重要的是,我们想确认我们没有遇到潜在的竞争条件。
从概念上讲,我们的移动应用程序的工作方式如下:
我们在加载移动网页时调用功能foo
。
在foo
结束时,如果计数器大于setTimeout
,我们会再次foo
再次调用0
(延迟一秒)。如果计数器点击0
,我们会加载新页面。超时保存在变量中。
如果点击了一个按钮,我们会调用函数do_tap
并清除第二步中保存的超时变量(并执行其他操作)。
do_tap
和foo
都会更新相同的网页元素,我们希望确认它们不会相互踩踏。
问题:
假设在执行foo
期间发生了点击。浏览器队列do_tap
是否会在foo
完成后开始执行?换句话说,我们保证一旦foo
开始,我们就永远看不到执行foo
和do_tap
交错了吗?
如果首先出现水龙头怎么办?保证do_tap
在foo
开始之前完成,对吧?
答案 0 :(得分:8)
除了Web worker和合作框架或窗口(这里没有使用)之外,Javascript在给定窗口中是单线程的,因此在该窗口中永远不会有两个执行线程同时运行。因此,在使用线程时,您不必担心可能是典型问题的竞争条件。
在幕后,Javascript有一个事件队列。您当前的执行线程将运行完成,然后当它完成时,javascript解释器将检查事件队列以查看是否还有更多事情要做。如果是这样,它会触发该事件并启动另一个执行线程。几乎所有事情都经历了事件队列(计时器,关键事件,调整大小事件,鼠标事件等)。
您可以阅读更多相关信息,并在my other answers之一中查看关于此主题的一系列相关参考资料。
答案 1 :(得分:5)
事件执行继续单线程直到事件处理完毕。在此之前,不会启动其他事件循环。
换句话说,当一个处理程序正在为某个事件运行时,任何其他事件的其他处理程序都不会中断它。
因此,问题1和问题2的答案都是“是”。 (当然,这是在禁止浏览器漏洞的情况下,但是如果你考虑到这一点,你就不会走得太远。它不像是有任何同步原语可以依赖。我说这只是因为有一段时间在此期间,Safari可以在运行另一个“DOMready”事件处理程序的过程中触发“DOMready”事件。但是,这显然是一个错误。)
答案 2 :(得分:0)
只要Do_tap()做的第一件事就是clearTimeout,在执行Do_tap()期间foo就没有机会运行。但是,如果在foo()这样的数据库请求中启动了异步进程,那么当foo()完成其请求时,可能存在潜在的等待以访问Do_tap()中的数据库,并且如果foo()具有可能的回调函数理论上在Do_tap()执行完毕后调用。
答案 3 :(得分:0)
我没有抓到其他任何人这样说,但我认为#2的答案是不同的浏览器实现可以并且确实区别于首先处理哪些排队事件。不,没有交错的可能性,但是语言规范无法保证是否首先处理setTimeout(func,0)或鼠标事件,并且在实践中可能很重要。而setTimeout(func,100) 保证比当前处理的事件期间收到的待处理事件处理得晚。
只是说。