如果node.js是单线程,那么为什么server.listen()返回?

我熟悉c ++和基于事件的系统。 我试图学习node.js并遇到了有趣的行为,我希望有人能够解释底下发生了什么。

我有一个看起来像一个程序

var http = require("http"); function main(){ // Console will print the message console.log('Server running at http://127.0.0.1:8080/'); var server = http.createServer(function (request, response) { // Send the HTTP header // HTTP Status: 200 : OK // Content Type: text/plain response.writeHead(200, {'Content-Type': 'text/plain'}); // Send the response body as "Hello World" response.end('Hello World\n'); }); server.listen(8080); //Why is this not blocking console.log('Main completed'); //main loop here prevents other stuff from working } main(); 

在像java或c这样的语言中,我希望有两件事。 server.listen提供了一个事件循环,这将导致server.listen永远不会返回。 或者,server.listen会产生一个新的线程,并在新的线程中运行事件循环。 然后它会调用console.log,然后返回并closures程序。

为了testing这个,我还在console.log下面添加了一个繁忙的循环。

 var http = require("http"); function main(){ // Console will print the message console.log('Server running at http://127.0.0.1:8080/'); var server = http.createServer(function (request, response) { // Send the HTTP header // HTTP Status: 200 : OK // Content Type: text/plain response.writeHead(200, {'Content-Type': 'text/plain'}); // Send the response body as "Hello World" response.end('Hello World\n'); }); server.listen(8080); //Why is this not blocking console.log('Main completed'); while(true){ console.log('hi'); } } main(); 

Server.listen会立即返回,然后按预期方式卡在忙碌循环中。 我的浏览器无法连接到预期的服务器。

如果我删除繁忙的循环,并返回到原来的代码console.log('主完成'); 被执行而不是退出程序,主线程跳回事件循环。

这个怎么用。 为什么主线程返回后主线程跳回到服务器代码?

编辑:我认为重新解决事件队列不存在于主要function,但它在哪里? 它拥有什么? 主函数什么时候参照运行呢?

http.createServer(handler)server.listen(port)想象成在浏览器中有点类似someElement.addEventListener('click', handler)

当你运行someElement.addEventListener('click', handler) ,它绑定一个事件监听器,当someElement触发click事件时,监听器将handler发送到callback队列。

server.listen(port) http.createServer(handler)结合的http.createServer(handler)以非常相似的方式工作。 http.createServer(handler)返回一个eventEmitterserver.listen(port)告诉node.js当在给定的端口上接收到一个http请求时,这个事件应该被触发。 因此,当请求进入时,事件被触发, handler被推送到callback队列。

在这一点上,事件循环callstack和callback队列如何交互只是一个简单的问题。 callstack是当前正在执行的函数栈, callback队列是等待执行的callback的集合,而事件循环是将callback从callback队列中取出并发送到调用堆栈

所以,从某种意义上说,事件循环是保持一切进行的东西,然而,如果你通过在你的callback函数中有一个同步的无限循环来阻止callstack的清空,事件循环就不会再运行,callback也不会执行,导致破碎/无反应的应用程序。

这里要理解的基本概念是事件循环和合作(非抢先式)多任务模型 。

server.listen调用在下面的事件循环中注册一个callback,并且该callback与其他每个注册的callback共享主执行线程。

当你把这个繁忙的循环放入时, server.listencallback从不会获得执行时间(事件引擎也不会),因为系统是非抢先式的 。 也就是说,没有任何callback可以打断任何其他callback – callback必须通过终止来将控制权交还给事件循环,于是事件循环将基于其排队的事件调用其他已注册的callback。

基本上http.createServer返回一个指向http.createServer的指针。 您可以将侦听器等附加到发出事件时将执行的对象。 这些是在asynchronous运行的事件循环内部处理的,并且不会阻塞主线程。 查看HTTP文档以获取有关HTTPEventEmitters更多信息。