JavaScript什么时候是同步的?

2022-08-30 00:45:27

我的印象是JavaScript总是异步的。但是,我已经了解到,在某些情况下它不是(即DOM操作)。关于它何时是同步的以及何时是异步的,是否有任何很好的参考?jQuery会影响这一点吗?


答案 1

JavaScript 始终是同步和单线程的。如果你在一个页面上执行一个JavaScript代码块,那么该页面上的其他JavaScript目前不会被执行。

JavaScript只是异步的,因为它可以进行例如Ajax调用。Ajax 调用将停止执行,其他代码将能够执行,直到调用返回(成功或以其他方式),此时回调将同步运行。此时将没有其他代码正在运行。它不会中断当前正在运行的任何其他代码。

JavaScript 计时器使用这种相同的回调进行操作。

将JavaScript描述为异步可能具有误导性。更准确地说,JavaScript是同步的,并且具有各种回调机制的单线程。

jQuery在Ajax调用上有一个选项,可以同步地进行它们(带有该选项)。初学者可能会错误地使用它,因为它允许更传统的编程模型,人们可能更习惯。它有问题的原因是,此选项将阻止页面上的所有JavaScript,直到它完成,包括所有事件处理程序和计时器。async: false


答案 2

JavaScript 是单线程的,具有同步执行模型。单线程意味着一次执行一个命令。同步意味着一次一个,即一次执行一行代码,以便代码出现。所以在JavaScript中,一次发生一件事。

执行上下文

JavaScript 引擎与浏览器中的其他引擎交互。在JavaScript执行堆栈中,底部有全局上下文,然后当我们调用函数时,JavaScript引擎会为相应的函数创建新的执行上下文。当被调用的函数退出时,将从堆栈中弹出其执行上下文,然后弹出下一个执行上下文,依此类推...

例如

function abc()
{
   console.log('abc');
}


function xyz()
{
   abc()
   console.log('xyz');
}
var one = 1;
xyz();

在上面的代码中,将创建一个全局执行上下文,并在此上下文中存储,其值将为1...当调用 xyz() 调用时,将创建一个新的执行上下文,如果我们在 xyz 函数中定义了任何变量,这些变量将存储在 xyz() 的执行上下文中。在xyz函数中,我们调用abc(),然后创建abc()执行上下文并将其放在执行堆栈上...现在,当 abc() 完成时,它的上下文将从堆栈中弹出,然后从堆栈中弹出 xyz() 上下文,然后全局上下文将被弹出...var one

现在关于异步回调;异步意味着一次多个。

就像执行堆栈一样,还有事件队列。当我们想要收到有关 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总是同步的。