在浏览器中如何执行异步JavaScript代码
与其他函数或操作同时运行的函数或操作被称为JavaScript中的异步函数或操作。异步函数使用稍后执行的回调函数。让我们看一个示例来说明这一点:
setTimeout(function greet() {
console.log("Welcome to GeeksforGeeks!");
}, 2000);
在上面的示例中,setTimeout是一个异步函数,它使用回调函数greet延迟2000毫秒后执行。因此,定时器到期后,消息会在控制台中打印出来。现在让我们看看上述操作在浏览器的JavaScript引擎中是如何执行的。
JavaScript异步执行的幕后工作:
JavaScript代码通过调用栈执行,由于调用栈中没有任何类似定时器的东西,我们无法延迟代码执行。因此,为了执行异步操作,我们使用浏览器全局对象中的setTimeout()等Web API的帮助。
有趣的是,setTimeout不是JavaScript的一部分,它是许多Web API(例如setTimeout、DOM API、fetch、LocalStorage、console、location等)之一,它们在浏览器的全局对象中可用。浏览器通过全局对象赋予JavaScript引擎访问这些Web API的能力。并且,因为window是一个全局对象,我们可以在不使用window关键字的情况下访问Web API。
为了看到异步代码在浏览器中的真实执行情况,让我们首先看一个异步代码的示例。
示例:
setTimeout(function greet(){
console.log("Welcome to GeeksforGeeks!");
}, 2000);
console.log("Hi!");
在这里, setTimeout在Web API环境中注册了回调函数greet,并附加了2秒的计时器。现在,由于所有的JavaScript代码都是通过调用栈执行的,JavaScript引擎将首先创建一个全局执行上下文,并执行最后一行代码,在控制台打印出“Hi!”。

一旦执行完成,全局执行上下文就会从调用栈中移除。现在,在计时器到期后,为了打印问候消息,我们需要以某种方式从回调函数中获取 greet 以便在调用栈中执行。这是通过 **** 事件循环 和 回调队列 完成的。
计时器到期后,回调函数被放入回调队列中,事件循环的工作是检查调用栈是否为空,如果为空,则将回调队列中的回调函数推入调用栈,然后将回调函数从回调队列中移除。然后,调用栈创建回调函数的执行上下文并执行它。

因此,代码的输出将是:
Hi!
Welcome to GeeksforGeeks!
在延迟2秒后,第二行将显示出来。这就是JavaScript中的异步操作在浏览器后台执行的方式。
极客教程