在玩过 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)要并发运行查询,db驱动程序必须具有某种线程/连接池,对吧?
2)在一个请求的范围内:发送两个查询后会发生什么?renderView不能被调用,因为查询还没有返回。我们如何等待查询返回?它应该计算未完成回调的数量,然后再继续吗?我的基本想法是;
onRequest -> 运行异步代码 -> 等待回调 -> 构造响应。在这种情况下,等待是阻塞的,所以你实际上需要为每个onRequest生成一个线程。如何“等待回调运行后再构造响应”?
3)db驱动程序如何通知事件循环已经完成,并且需要调用其回调以获取查询结果?
4)事件循环如何运行我们使用onRequest事件创建的匿名函数中的回调?这是闭包概念介入的地方,上下文在回调函数中被“保存”吗?
5)现在我们有了db结果,如何继续执行renderView/res.write/res.end
部分?