Node.js事件循环如何工作?

时间:2011-07-20 20:56:35

标签: node.js evented-io

播放Node.js并阅读async i / o&偶然编程很多我留下了一些问号。

考虑以下(伪)代码:

var http = require('http');

function onRequest(request, response)
{
    // some non-blocking db query
    query('SELECT name FROM users WHERE key=req.params['key']', function (err, results, fields) {
        if (err) {
            throw err;
        }
        username = results[0];
    });

    // some non-blocking db query
    query('SELECT name FROM events WHERE key=req.params['key']', function (err, results, fields) {
        if (err) {
            throw err;
        }
        event_name = results[0];
    });

    var body = renderView(username, event_name, template);
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write(body);
    res.end();
};

http.createServer(onRequest).listen(8888);

// request A: http://127.0.0.1:1337/?key=A
// request B: http://127.0.0.1:1337/?key=B

(我认为)我理解事件循环的基础知识;使用libev,Node.js创建一个事件循环,轮询(epoll / kqueue / ...)一堆文件描述符,以查看是否触发了任何事件(新连接,可写,数据可用等)。如果有新请求,则事件循环调用传递给createServer的匿名函数。我不明白的是之后会发生什么:

1)要同时运行查询,db驱动程序必须有某种线程/连接池,对吗?

2)在一个请求的范围内:发送两个查询后会发生什么?无法调用renderView,因为查询尚未返回。我们如何等待查询返回?是否应该继续计算待处理的回调?我的基本想法是;

onRequest - >运行异步代码 - >等待回调 - >构建响应。在这种情况下等待将是阻塞,因此您实际上需要为每个onRequest生成一个线程。如何“在构建响应之前等待回调运行”?

3)数据库驱动程序如何通知事件循环它已完成并且需要使用查询结果调用它的回调?

4)事件循环如何运行我们使用onRequest事件创建的匿名函数内的回调?这是闭包概念出现在回调函数中“保存”上下文的地方吗?

4)现在我们有了db结果,我们如何继续执行renderView/res.write/res.end部分?

2 个答案:

答案 0 :(得分:6)

运行并行异步代码模式:

要“等待来自两个异步函数的结果”,您可以执行以下操作:在两个异步调用中,回调检查两个结果,如果一切就绪,请调用DoSomethingWithTwoDependantResults。

在您的示例中,您可能需要按顺序执行查询:

query(sql1, function(sqlres1) {
    query(sql2, function(sqlres2) {
        writeResultUsingDataFrom(sqlres1, sqlres2);
    }
});

您的原始代码,已修改为并行执行两个查询:

function writeReply(res, template, username, event_name)
{
    var body = renderView(username, event_name, template);
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write(body);
    res.end();
} 

function onRequest(request, response)
{
    // some non-blocking db query
    query('SELECT name FROM users WHERE key=req.params['key']', function (err, results, fields) {
        if (err) {
            throw err;
        }
        username = results[0];
        if (username && event_name)
            writeReply(res, template, username, event_name);
    });

    // some non-blocking db query
    query('SELECT name FROM events WHERE key=req.params['key']', function (err, results, fields) {
        if (err) {
            throw err;
        }
        event_name = results[0];
        if (username && event_name)
            writeReply(res, template, username, event_name);

    });
};

答案 1 :(得分:3)

你见过this吗?我仍然掌握了这一切,我无法详细回答你的问题,但基本上你对线程池是正确的...... Ryan在视频中解释了很多。

编辑:大约一年之后,this one,当他详细介绍时。