Nodejs 线程

2016/01/01 JavaScript

NodeJS是单线程异步非阻塞的。

同步异步区别

  • 同步:CPU需要计算10个数据,每计算一个结果后,将其写入磁盘,等待写入成功后,再计算下一个数据,直到完成 同步强调的是事件的连续性,强调过程。
  • 异步: CPU需要计算10个数据,每计算一个结果后,将其写入磁盘,不等待写入成功与否的结果,立刻返回继续计算下一个数据,计算过程中可以收到之前写入是否成功的通知,直到完成。 异步强调效率,强调结果。
function test() {
    for (var i = 0; i < 10; i++) {
        console.log(new Date);
        setTimeout(function(){}, 2000); //睡眠2秒,然后再进行一下次for循环打印
    }
};
test();

观察结果发现都是在14:53:22同一个时间点打印的,根本就没有睡眠2秒后再执行下一轮循环打印!这是为什么?从官方的文档我们看出setTimeout是第二个参数表示逝去时间之后在执行第一个参数表示的callback函数,因此我们可以分析, 由于Node.js的异步机制,setTimeout每个for循环到此之后,都注册了一个2秒后执行的回调函数然后立即返回马上执行console.log(new Date),导致了所有打印的时间都是同一个点,因此我们修改for循环的代码如下:

for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(new Date);
}, 2000);
}

神奇,仍然是同一个时间点,见鬼!冷静下来分析,时刻考虑异步,for循环里每次setTimeout注册了2秒之后执行的一个打印时间的回调函数,然后立即返回,再执行setTimeout,如此反复直到for循环结束,因为执行速度太快,导致同一个时间点注册了10个2秒后执行的回调函数,因此导致了2秒后所有回调函数的立即执行。 我们在for循环之前添加console.log(“before FOR: “ + new Date)和之后console.log(“after FOR: “ + new Date),来验证我们的推测 由此可以窥视出Node.js异步机制的端倪了,在for循环中的代码于其后的代码几乎在一个单位秒内完成,而定时器中的回调函数则按要求的2秒之后执行,也是同一秒内执行完毕。那么如何实现最初C语言每隔2秒打印一个系统时间的需求函数呢,我实现了如下一个wsleep函数,放在for循环中,可以达到该目的:

function wsleep(milliSecond) {
    var startTime = new Date().getTime();
    while(new Date().getTime() <= milliSecond + startTime) {
    }
}

事件

Node里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。 你可以通过require(“events”);来访问该模块 可以看出我们的事件是定义在events.EventEmitter 的实例,所以我们先实例化这个类

//引入events模块
var events = require("events");
//实例化events.EventEmitter对象
var event = new events.EventEmitter();

我们定义了一个myevent事件,下面我们使用它

//使用事件
event.emit("myevent");

下面一些事件方法

删除一个事件
event.removeListener("myevent",function(){
    console.log("现在删除这个once_event事件");
});
//删除所有事件,或者删除某些事件
event.removeAllListeners("myevent");
//添加一个一次性事件,事件被触发后就被删除
event.once("once_event",function(){
    console.log("这是个一次性事件,事件被触发后就被删除");
});
//触发一次性事件
event.emit("once_event");
//返回指定事件的listener数组
console.log(event.listeners('myevent'));

下面给我们的对象添加事件

var util = require("util");
var events = require("events"); 
//让MyEvent继承event.EventEmitter,使用的是util.inherits这个工具来继承
function MyEvent() {
    events.EventEmitter.call(this);
}
util.inherits(MyEvent, events.EventEmitter); 
//MyEvent类的write方法触发了data这个事件
MyEvent.prototype.write = function(data) {
    this.emit("data", data);//触发DATA事件
    return this;//返回对象,方便链式调用
}
//实例化MyEvent对象,
var myevent = new MyEvent();
//监听myevent的data事件
myevent.on("data",function(data){
    console.log("事件的回调:"+data);
});

//用write方法触发data事件
myevent.write("一个操作后,触发了MyEvent对象的data事件");

Search

    Table of Contents