Javascript(不仅是 node.js,甚至你的网络浏览器,无论它是 Chrome、Safari、IE 还是 Edge)都是单线程的。 javascript解释器的结构一般可以用如下伪代码来描述:
script_to_exec = compile_js_from_files()
do {
event_queue = execute_javascript(script_to_exec)
completed_events = wait_for_events()
for_each (event from completed_events) {
this_event = event_queue.find_one_matching(event)
script_to_exec = this_event.callback
}
} while (there_is_pending_events)
您可能会注意到上面的代码中根本没有线程代码。我们在wait_for_events() 中所做的只是使用操作系统提供的异步 I/O API。根据操作系统,这可能类似于 POSIX select() 或 Linux 和 OSX poll() 或 BSD epoll() 或 Windows 重叠 I/O 功能。 Node 使用 libuv 库,它会在编译时自动选择最佳 API。
循环第 1 轮
好的。所以第一轮循环它执行你的整个代码。这会在您设置 express 时设置 TCP 套接字侦听器。然后卡在wait_for_events()
第一个 HTTP 请求导致 wait_for_events() 返回。这会导致 Express 遍历您的中间件和路由列表以找到要执行的路由。它找到您的路线并调用wait(),后者调用setTimeout(),将其回调添加到计时器列表中。
循环第二轮
由于在await 返回之前没有更多的 javascript 可以执行,我们再次循环并再次卡在wait_for_events()。
第二个 HTTP 请求导致 wait_for_events() 返回。这会导致 Express 遍历您的中间件和路由列表,并重复我之前描述的内容。
循环第 3 轮
由于在await 返回之前没有更多的 javascript 可以执行,我们再次循环并再次卡在wait_for_events()。
第三个 HTTP 请求导致 wait_for_events() 返回。这会导致 Express 遍历您的中间件和路由列表,并重复我之前描述的内容。
循环第 4 轮
再次,我们再次循环并卡在wait_for_events()。
第一个await wait() 计时器到期。这会导致wait_for_events() 返回并且javascript 确定事件是wait 的计时器,因此它会继续处理第一个HTTP 请求。这会导致 Express 发送响应。
循环第 5 轮
我们再次循环并等待wait_for_events()。
第二个await wait() 计时器到期。这会导致wait_for_events() 返回并且javascript 确定该事件是该wait 的计时器,因此它会继续处理第二个HTTP 请求。这会导致 Express 发送响应。
循环第 6 轮
我们再次循环并等待wait_for_events()。
第三个await wait() 计时器到期。这会导致 wait_for_events() 返回,并且 javascript 确定事件是该 wait 的计时器,因此它继续处理第三个 HTTP 请求。这会导致 Express 发送响应。
循环第 7 轮
我们再次循环,再次卡在wait_for_events() 等待更多 HTTP 请求...
总结
基本上,javascript 可以等待并行处理多个事情。这是因为它最初是一种 GUI 脚本语言,必须能够等待鼠标点击、键盘输入等。但它一次只能执行一条指令(当然,除非你故意使用功能执行额外的进程/线程,例如网络工作者或工作线程)。
如果您想知道为什么人们将 node.js 用于高性能 Web 服务器,我已经为这个相关问题写了一个答案,解释了为什么 node 速度快:Node js architecture and performance
以下是我的一些其他答案,涉及到有关异步执行的不同级别的详细信息:
I know that callback function runs asynchronously, but why?
Is my understanding of asynchronous operations correct?
Is there any other way to implement a "listening" function without an infinite while loop?
node js - what happens to incoming events during callback excution
I know that callback function runs asynchronously, but why?