9

在玩过 Node.js 并阅读了很多关于异步 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)要同时运行查询,数据库驱动程序必须有某种线程/连接池,对吗?

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

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

3) db 驱动程序如何通知事件循环它已经完成并且它所具有的回调需要与查询结果一起调用?

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

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

4

2 回答 2

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);

    });
};
于 2011-07-21T01:44:43.783 回答
3

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

编辑:大约一年后,当他更详细地介绍时。

于 2011-07-20T21:09:22.720 回答