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

时间:2015-11-03 19:55:22

标签: node.js

我熟悉c ++和java中基于事件的系统。我试图学习node.js并遇到有趣的行为,我希望有人可以解释幕后发生的事情。

我的程序看起来像

<domains>

在java或c等语言中我会期待两件事。 server.listen都提供了一个事件循环,它会导致server.listen永远不会返回。或者server.listen生成一个新线程并在新线程中立即运行事件循环。然后它将调用console.log,然后返回并关闭该程序。

为了测试这个,我还在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');

    //main loop here prevents other stuff from working
}

main();

Server.listen立即返回,然后按预期陷入繁忙循环。我的浏览器无法连接到服务器,这是预期的。

如果我删除busy循环并返回原始代码,一旦console.log('Main completed');执行而不是程序退出,主线程跳回事件循环。

这是如何工作的。为什么主线程返回后主线程会跳回到服务器代码中?

编辑: 我认为重新解决了主函数中不存在事件队列但它在哪里?拥有什么?什么时候主函数会参考它运行?

3 个答案:

答案 0 :(得分:5)

http.createServer(handler)server.listen(port)视为与浏览器中的someElement.addEventListener('click', handler)类似。

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

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

此时,事件循环callstack和回调队列的交互方式只是一个简单的问题。 callstack 是当前正在执行的函数堆栈,回调队列是等待执行的回调集合,事件循环是什么从回调队列中提取回调并将其发送到 callstack

因此,从某种意义上说,事件循环是保持一切运行的原因,但是,如果通过在其中一个回调中阻塞callstack使其无法循环,则事件循环永远不会再次运行并且回调永远不会被执行导致应用程序损坏/无响应。

答案 1 :(得分:1)

这里要理解的基本概念是事件循环和cooperative (non-preemptive) multitasking model

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

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

答案 2 :(得分:0)

基本上Router::prefix('api', function ($routes) { $routes->extensions(['json', 'xml']); $routes->resources('Users'); }); 会返回指向http.createServer的指针。您可以将侦听器等附加到将在发出事件时执行的对象。这些是在事件循环内部处理的,它是异步运行的,不会阻塞主线程。有关EventEmitterHTTP

的详细信息,请查看HTTP文档