如果 Javascript 是单线程的,它如何实现异步?

2025-05-24

如果 Javascript 是单线程的,它如何实现异步?

JavaScript 是单线程语言。这意味着它只有一个调用堆栈和一个内存堆。正如预期的那样,它按顺序执行代码,并且必须完成一段代码才能继续执行下一段。它是同步的,但有时这可能会造成危害。例如,如果一个函数需要一段时间才能执行,或者需要等待某些事情,它会在此期间冻结所有进程。

窗口警报功能就是一个很好的例子。alert("Hello World")

除非你点击“确定”并关闭警报,否则你根本无法与网页进行任何交互。你被困住了。

那么我们如何使用 Javascript 获取异步代码呢?

这得感谢 JavaScript 引擎(V8、Spidermonkey、JavaScriptCore 等等),它提供了一些 Web API 来在后台处理这些任务。调用栈会识别 Web API 的函数,并将它们交给浏览器处理。浏览器完成这些任务后,它们就会返回,并作为回调函数被推送到调用栈。

打开控制台,输入以下命令,window然后按回车键。您将看到 Web API 提供的大部分功能,包括 Ajax 调用、事件监听器、fetch API 和 setTimeout。JavaScript 使用 C++ 等低级编程语言在后台执行这些操作。

让我们看一个简单的例子,在你的控制台中运行此代码:

console.log("first")
setTimeout(() => {
    console.log("second")
}, 1000)
console.log("third")
Enter fullscreen mode Exit fullscreen mode

我们得到了什么?

first
third
undefined
second
Enter fullscreen mode Exit fullscreen mode

感觉很奇怪,对吧?好吧,让我们逐行分解一下:

console.log("first")首先在堆栈上,因此它会被打印出来。接下来,引擎注意到 setTimeout 函数,它不会被 JavaScript 处理,因此会将其推送到 WebAPI 进行异步处理。调用堆栈继续执行,不再关心传递给 Web API 的代码,而是console.log("three")直接打印出来。

接下来,JavaScript 引擎的事件循环启动,就像一个小孩在旅途中问“我们到了吗?”一样。它开始触发,等待事件被推送进去。由于setTimeout尚未完成,它undefined默认返回 ,因为它还没有被赋值。一旦回调最终命中,我们就会console.log("second")打印出来。

有一个非常好的网站,可以放慢这一切的速度并展示这一切的发生。

http://latentflip.com/loupe

我建议你在这个沙盒里尝试一下,这样可以帮助你巩固理解。它帮助我了解了异步代码在 JavaScript 单线程环境下是如何工作的。

文章来源:https://dev.to/bbarbour/if-javascript-is-single-threaded-how-is-it-asynchronous-56gd
PREV
空白页是什么颜色?请证明一下,因为页面有点白,我得说,超越正文。这有什么关系?白色和透明之间有什么区别?空白画布是什么颜色?
NEXT
React & Node 教程 - 5 小时完成完整的电子商务 [2020]