JavaScript何时同步?
我一直认为JavaScript总是异步的。 但是,我已经了解到,有些情况并非如此(即DOM操作)。 是否有一个很好的参考,什么时候会是同步的,什么时候会是异步的? jQuery是否会影响这个呢?
JavaScript始终是同步和单线程的。 如果您在页面上执行JavaScript代码块,那么该页面上的其他任何JavaScript都不会执行。
JavaScript只是一种异步,例如,它可以使Ajax调用。 代码将停止执行,直到调用返回(成功或以其他方式),此时回调将同步运行。 目前没有其他代码正在运行。 它不会中断任何其他正在运行的代码。
JavaScript定时器使用这种相同的回调。
将JavaScript描述为异步可能是误导性的。 更准确地说,JavaScript是同步的,并且具有各种回调机制的单线程。
jQuery在Ajax调用上有一个选项来同步(使用async: false
选项)。 初学者可能会试图错误地使用它,因为它允许使用更传统的编程模型。 这个问题的原因是,这个选项将阻止页面上的所有 JavaScript,直到完成,包括所有的事件处理程序和定时器。
JavaScript是单线程的,并有一个同步执行模型。 单线程意味着一次执行一个命令。 同步意味着一次一个,即一行代码正在执行,以便代码出现。 所以在JavaScript中,有一件事正在发生。
执行上下文
JavaScript引擎与浏览器中的其他引擎进行交互。 在JavaScript执行堆栈底部有全局上下文,然后当我们调用函数时,JavaScript引擎为各个函数创建新的执行上下文。 当被调用的函数退出时,执行上下文从堆栈弹出,然后弹出下一个执行上下文,等等。
例如
function abc() { console.log('abc'); } function xyz() { abc() console.log('xyz'); } var one = 1; xyz();
在上面的代码中,将会创建一个全局执行上下文,在这个上下文中var one
将被存储,其值将是1 …当调用xyz()调用时,将创建一个新的执行上下文,如果我们已经定义xyz函数中的任何变量都会将这些变量存储在xyz()的执行上下文中。 在xyz函数中,我们调用abc(),然后创建abc()执行上下文并将其放在执行堆栈上。现在,当abc()完成时,上下文从堆栈中弹出,然后xyz堆栈,然后全局上下文将被弹出…
现在关于异步回调 异步意味着一次超过一个。
就像执行堆栈一样,有事件队列 。 当我们想要在JavaScript引擎中通知某个事件时,我们可以监听该事件,并将该事件放在队列中。 例如,一个Ajax请求事件或HTTP请求事件。
每当执行堆栈为空时,如上面的代码示例所示,JavaScript引擎定期查看事件队列,查看是否有任何事件要通知。 例如在队列中有两个事件,一个ajax请求和一个HTTP请求。 它还会查看是否有需要在该事件触发器上运行的函数…因此,JavaScript引擎会得到有关该事件的通知,并知道在该事件上执行的相应函数…因此,JavaScript引擎会调用处理函数,在这个例子中,例如AjaxHandler()将被调用,并且像函数被调用时一样,它的执行上下文被放置在执行上下文中,现在函数执行结束,并且事件ajax请求也被从事件队列中移除…当AjaxHandler()完成执行堆栈时为空,所以引擎再次查看事件队列并运行队列中下一个HTTP请求的事件处理函数。 请记住,事件队列只有在执行堆栈为空时才会被处理。
例如,请参阅下面的代码,解释Javascript引擎执行堆栈和事件队列处理。
function waitfunction() { var a = 5000 + new Date().getTime(); while (new Date() < a){} console.log('waitfunction() context will be popped after this line'); } function clickHandler() { console.log('click event handler...'); } document.addEventListener('click', clickHandler); waitfunction(); //a new context for this function is created and placed on the execution stack console.log('global context will be popped after this line');
和
<html> <head> </head> <body> <script src="program.js"></script> </body> </html>
现在运行网页并点击页面,在控制台上看到输出。 输出将是
waitfunction() context will be popped after this line global context will be emptied after this line click event handler...
JavaScript引擎按照执行上下文部分中的说明同步运行代码,浏览器将事件异步放入事件队列中。 所以花费很长时间才能完成的功能会中断事件处理。 像事件一样在浏览器中发生的事情是通过JavaScript来处理的,如果有一个监听器应该运行,那么当执行堆栈是空的时,引擎会运行它。 事件按照发生的顺序进行处理,所以异步部分是关于发动机外部发生的事情,即当外部事件发生时发动机应该做什么。
所以JavaScript总是同步的。
JavaScript是单线程的,并且一直处理正常的同步代码流执行。
JavaScript可以具有的异步行为的好例子是事件(用户交互,Ajax请求结果等)和计时器,基本上可以随时发生的行为。
我会建议你看看下面的文章:
- JavaScript定时器的工作原理
该文章将帮助您理解JavaScript的单线程本质,以及定时器如何在内部工作以及异步JavaScript执行的工作方式。