3、事件驱动
总结上面的过程可以发现,Node.js的核心是使用事件驱动模式实现了异步I/O,为了更具体、更清晰的理解和接受这个事实,我们用代码来描述Node.js的事件驱动模型:
3.1、事件队列
首先,我们需要定义一个事件队列,既然是队列,那就是一个先进先出(FIFO)的数据结构,我们用JS的数组来描述,如下:
/**
* 定义事件队列
* 入队:unshfit()
* 出队:pop()
* 空队列:length == 0
*/
eventQueue:[],为了方便理解,我们规定:数组的第一个元素是队列的尾部,数组的最后一个元素是队列的头部, unshfit 就是在尾部插入一个元素,pop就是从头部弹出一个元素,这样就实现了一个简单的队列。
3.2、接收请求
定义一个总的入口来接收用户请求,如下所示:
/**
* 接收用户请求
* 每一个请求都会进入到该函数
* 传递参数request和response
*/
processHttpRequest:function(request,response){ //定义一个事件对象
var event = createEvent({
params:request.params, //传递请求参数
result:null, //存放请求结果
callback:function(){} //指定回调函数
});
//在队列的尾部添加该事件
eventQueue.unshift(event);
},
这个函数很简单,就是把用户的请求包装成事件,放到队列里,然后继续接收其他请求。
3.3、事件循环
当主线程处于空闲时就开始循环事件队列,所以,我们再定义一个事件循环的函数:
/**
* 事件循环主体,主线程择机执行
* 循环遍历事件队列
* 处理事件
* 执行回调,返回给上层
*/
eventLoop:function(){
//如果队列不为空,就继续循环
while(this.eventQueue.length > 0){
//从队列的头部拿出一个事件
var event = this.eventQueue.pop();
//如果是IO任务
if(isIOTask(event)){
//从线程池里拿出一个线程
var thread = getThreadFromThreadPool();
//交给线程处理
thread.handleIOTask(event)
}else {
//非IO任务处理后,直接返回结果
var result = handleEvent(event);
//最终通过回调函数返回给V8,再由V8返回给应用程序
event.callback.call(null,result);
}
}
},主线程不停的检测事件队列,对于IO任务就交给线程池来处理,非IO任务就自己处理并返回。
3.4、线程池
线程池接到任务以后,直接处理IO操作,比如读取数据库:
当IO









