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

发生这种情况的一个很好的例子是窗口警报功能。alert("Hello World")

在您点击 OK 并关闭警报之前,您根本无法与网页交互。你被困住了。

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

好吧,我们要感谢 Javascript 引擎(V8、Spidermonkey、JavaScriptCore 等),它有在后台处理这些任务的 Web API。调用堆栈识别 Web API 的函数并将它们交给浏览器处理。一旦浏览器完成了这些任务,它们就会返回并作为回调推送到堆栈中。

打开您的控制台并输入,window然后按回车键。您将看到 Web API 所提供的大部分内容。这包括诸如 ajax 调用、事件侦听器、获取 API 和 setTimeout 之类的东西。Javascript 使用 C++ 等低级编程语言在幕后执行这些操作。

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

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

我们得到了什么?

第一
第三
未定义
第二

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

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

https://stackoverflow.com/questions/51007636/how-javascript-single-threaded-and-asynchronous