Node.js回调机制及事件驱动模型

Node.js回调机制及事件驱动模型

Posted by wang chong on January 23, 2019

什么是回调

函数的调用分为三种:同步调用、回调和异步调用。

回调是一种双向调用

被调用的一个函数在被调用的使用会反过来调用它的主调函数,这种情况叫做双向调用

JavaScript通过回调函数来实现回调。

阻塞与非阻塞

在NodeJS入门就说到Node是非阻塞是IO,什么是阻塞什么是非阻塞呢?

  1. 阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态
  2. 阻塞就是做不完不准回来。
  3. 非阻塞就是当函数执行的时候,把函数的执行权先交给外界环境,等待其中IO完成之后,再把执行权返回给该函数。(通俗的将:非阻塞就是你先做,我先看看有其他事没有,完了告诉我一声。)

Nodejs的回调函数

阻塞式的代码

//引入node中的文件系统模块
const fs = require('fs');
//同步读取,读取的信息按照16进制保存的
let data = fs.readFileSync('test.js');      
console.log(data.toString());

非阻塞的代码

const fs = require('fs');
//异步读取
    //第一个参数是读取文件的文件路径
    //第二个参数是异步读取文件的回调函数
fs.readFile('test.js',function(err,data){
    //回调函数的第一个参数是err
    //第二个参数是读取的信息。
    if(err){
        return console.log(err);
    }
    console.log(data.toString());
})
console.log('程序执行完毕');

NodeJS的事件驱动模型

nodejs是一个单进程单线程的运行程序,并不能并发的去完成更多的事情,只能通过事件回调实现这种并发的效果。nodejs中的每一个API都是异步执行的,而且都是作为一个独立的线程在运行,使用异步函数调用就可以使用这种机制来并发处理。

nodejs中的事件机制都是依据观察者模式来设计的。

事件处理流程

每当一个事件注册了之后就会把这个事件放入事件队列中,然后通过事件轮询依次触发事件。

事件与事件绑定

NodeJS通过引入events模块,来进行事件的绑定流程如下:

1、引入events模块

const events = require('events');

2、创建eventEmitter对象

const eventEmitter = new events.EventEmitter();

3、绑定事件处理程序

//事件处理函数
const connectHandle = () => {
    console.log('connectHandle');
}   
//事件绑定
    //使用eventEmitter.on方法绑定事件
        //第一个参数:事件名称
        //第二个参数:事件处理函数
eventEmitter.on('connection',connectHandle);   

4、触发事件

eventEmitter.emit('connection');

其他事件方法

eventEmitter.addListener(event,handler)

用于绑定事件,on方法是它的别名。

eventEmitter.addListener('test',()=>{
    console.log('hello world');
}) 
eventEmitter.once(event,handler)

用于绑定事件,绑定的事件只触发一次。

eventEmitter.once('test1',()=>{
    console.log('test1');
})
eventEmitter.setMaxListeners(num)

设置事件绑定处理函数的最大数量。参数为数值。

eventEmitter.setMaxListeners(2); 
eventEmitter.listeners(event)

用于获取指定事件的事件处理函数

console.log(eventEmitter.listeners('test'));
eventEmitter.removeListener(event,handler)

用于解除指定事件的指定处理函数。

const handler = ()=>{
	console.log(123);
}
eventEmitter.on('test',handler);
eventEmitter.removeListener('test',handler);
eventEmitter.removeAllListeners(event);

用于解除指定事件的所有处理函数。

eventEmitter.removeAllListeners('test');

EventEmitter类自身的方法

EventEmitter.listenerCount(obj,event)

可用来获取某个对象的指定事件的事件处理函数的数量。两个参数:

  1. 第一个参数是用于指定目标是哪个对象
  2. 二个参数是指定哪个事件
EventEmitter.listenerCount(http,'request');

EventEmitter类自身的事件

newListener事件

当对继承了EventEmitter类的子类实例对象绑定事件处理函数 的时候,都会触发EventListener类的newListener事件。

在事件处理函数中,可使用两个参数,其中第一个参数为被绑定的事件名,第二个参数为被绑定的事件处理函数。

eventEmitter.on('newListener',(eventName,handler)=>{
	console.log(eventName);
})
eventEmitter.on('request',()=>{
	console.log('listener');
})
removeListener事件

当对继承了EventEmitter类的子类实例对象取消事件处理函数时,都将触发EventEmitter类的removeListener事件。

在事件处理函数中,可使用两个参数,其中第一个参数为被取消事件处理函数的事件名,第二个参数为被取消的事件处理函数。

eventEmitter.on('removeListener',(eventName,handler)=>{
		console.log(eventName);
})
eventEmitter.removeAllListeners('request');