如果node.js是单线程的,那么为什么server.listen()会返回? 我熟悉C++中的事件系统,也熟悉java。我试图学习node.js,遇到了有趣的行为,我希望有人能解释引擎盖下发生了什么

如果node.js是单线程的,那么为什么server.listen()会返回? 我熟悉C++中的事件系统,也熟悉java。我试图学习node.js,遇到了有趣的行为,我希望有人能解释引擎盖下发生了什么,node.js,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 h

我有一个程序看起来像

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永不返回。或server.listen生成一个新线程,并在新线程中运行事件循环,然后立即返回。然后调用console.log,然后返回并关闭程序

为了测试这一点,我还在console.log下面添加了一个busy循环,如下所示

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('Main completed');执行而不是退出程序时,主线程跳回事件循环

这是如何工作的。为什么在主线程返回后,主线程跳回服务器代码

编辑:
我认为重新解决了事件队列在主函数中不存在的问题,但它在哪里?什么拥有它?主函数在什么时候运行以引用它?

基本上
http。createServer
返回指向
事件发射器的指针。您可以将侦听器等附加到将在发出事件时执行的对象。这些是在异步运行的事件循环内部处理的,不会阻塞主线程。查看文档以了解有关
HTTP
EventEmitters

的更多信息这里要了解的基本概念是事件循环和

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


当您抛出繁忙循环时,
server.listen
回调永远不会得到执行时间(就这点而言,事件引擎也不会),因为系统是非抢占式的。也就是说,任何回调都不能中断任何其他回调-回调必须通过终止将控制权交还给事件循环,因此事件循环将根据它已排队的事件调用其他已注册的回调。

想想http.createServer(handler)
server.listen(端口)
类似于浏览器中的
someElement.addEventListener('click',handler)

运行
someElement.addEventListener('click',handler)
时,它绑定一个事件侦听器,当在
someElement
上触发click事件时,该事件侦听器将
handler
发送到回调队列

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

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


因此,从某种意义上说,事件循环是保持一切正常运行的因素,但是,如果您通过在其中一个回调中使用同步无限循环来阻止调用堆栈清空,那么事件循环将不会再次运行,回调也不会执行,从而导致应用程序中断/无响应。

有用:我了解事件循环的这一部分。我的问题涉及到这样一个事实,即主线程退出并看起来像是跳回到另一个点。因为server.listen这是异步函数。如果调用是异步的,那么为什么忙循环会阻止事件被处理?因为忙循环也会阻止所有回调被处理;在清除调用堆栈之前,事件循环无法运行。但是,主函数的末尾如何知道跳回事件循环?该主函数的级别高于作为引擎本身一部分的事件循环。当主函数启动时,事件循环静止不动。当主函数停止时,事件循环开始。这是节点的本质:“事件循环侦听事件,没有回调运行”的状态本质上是节点的基态,我想我明白了。主功能本身就是一个已处理的事件?因此,当主函数完成时,它将返回到引擎中的事件循环。不,它是一个函数。:)您的调用堆栈看起来有点像:
global->main
直到
main
返回,
global
无法返回。在
global
返回之前,调用堆栈不会为空,并且只返回事件循环。。调用堆栈为空时循环<代码中的code>main在while循环完成之前不会返回。。。如果你仍然不太理解事件循环/回调队列/调用堆栈,请观看此视频。你的回答帮助很大。我不是在问事件循环是如何工作的。它在哪里更重要?我的印象是,这是在听。但我现在明白,它不是,但它仍然必须在某个地方。例如在java中。如果您要设置事件队列。首先创建一个充当事件队列的执行器