node 之EventEmitter实现

简介: node 根据事件驱动,那基本都是回调,最常用的叫发布订阅模式,什么叫发布订阅呢?对比观察者模式,前者是主动地,后者是被动的

node 根据事件驱动,那基本都是回调,最常用的叫发布订阅模式,什么叫发布订阅呢?对比观察者模式,前者是主动地,后者是被动的

//发布订阅模式
//将时间放到数组中,当真的发生时在执行

//let  EventEmitter = require('events');
let  EventEmitter = require('./EventEmitter');
let {inherits} = require('util');
function Girl(){}
inherits(Girl,EventEmitter);
let girl = new Girl;
let cry = () =>{
    console.log('cry')
}
let drink = () =>{
    console.log('drink')
}
girl.on('one',cry)
girl.on('two',drink)

girl.emit('two')
复制代码

可以正常输出1.txt里面的内容,那么EventEmitter是如何实现的呢?

EventEmitter实现

EventEmitter骨架

function EventEmitter(){

}
EventEmitter.prototype.on = function(type,callback){

}
EventEmitter.prototype.emit = function(type){
    
}
module.exports = EventEmitter;
复制代码

EventEmitter.on

function EventEmitter(){
    this._events = {};
}
//this._events = {one:[cry],two:[drink]}

EventEmitter.prototype.on = function(type,callback){
    //如果实例不存在则会创建一个空对象
    if(!this._events)  this._events = Object.create(null) //继承会找不到event ,直接实例可以, Cannot read property 'one' of undefined 初始化this._events
    // this._events ={}  和 this._events = Object.create(null) 的区别 前者原型指针指向object链,后者没有任何属性,后者可以避免第三方继承
    if(this._events[type]){ // 查看事件名称是否存在
        this._events[type].push(callback)
    }else{
        this._events[type] = [callback] //将事件绑定在对象上
    }
}
复制代码

**EventEmitter.newListener || EventEmitter.addListener **

EventEmitter.addListener =  EventEmitter.prototype.on = function(type,callback){
    //如果实例不存在则会创建一个空对象
    if(!this._events)  this._events = Object.create(null)
    if(this.newListener && this._events['newListener'] && this._events['newListener'].length>0){
        if(type != 'newListener'){
            this._events['newListener'].forEach(fn => fn(type))
        }
    }//继承会找不到event ,直接实例可以, Cannot read property 'one' of undefined 初始化this._events
    // this._events ={}  和 this._events = Object.create(null) 的区别 前者原型指针指向object链,后者没有任何属性,后者可以避免第三方继承
    if(this._events[type]){ // 查看事件名称是否存在
        this._events[type].push(callback)
    }else{
        this._events[type] = [callback] //将事件绑定在对象上
    }
}
复制代码

EventEmitter.defaultMaxListeners || emitter.getMaxListeners() || emitter.setMaxListeners()

EventEmitter.defaultMaxListeners = 10; //默认最大监听数
EventEmitter.prototype.setMaxListeners = function(count){
    this._count = count;
}
EventEmitter.prototype.getMaxListeners = function(){
    return  this._count || EventEmitter.defaultMaxListeners
}
EventEmitter.addListener = EventEmitter.prototype.on = function(type,callback){
    ...
    if(this._events[type].length === this.getMaxListeners()){
        console.warn('memeoy link detected')
    }
}
复制代码

EventEmitter.eventNames || listeners

EventEmitter.prototype.eventNames = function(){
    return Object.keys(this._events)
}
EventEmitter.prototype.listeners = function(type){
    return this._events[type]
}
复制代码

removeListener || removeAllListeners

//找到数组里的方法对应的移除掉即可
EventEmitter.prototype.removeListener = function(type,callback){
    if (typeof callback !== 'function')  throw new TypeError('"callback" argument must be a function');
    if(this._events[type]){
        // filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
        //this._events[type] = this._events[type].filter(fn => fn != callback)
        //一次只删除一个,不是删除所有相同的type,应该用下面方法
        // for(let i = 0;i < this._events[type].length;i++){
        //     if(this._events[type][i] == callback){
        //         this._events[type].splice[i]
        //         break;
        //     }
        // }
        //同上效果
        this._events[type].splice(this._events[type].indexOf(callback),1)
    }
}
EventEmitter.prototype.removeAllListeners = function(type){
    if(this._events[type]){
        return this._events[type] = Obj.create(null)
    }else{

    }
}
复制代码

EventEmitter.once

EventEmitter.prototype.once = function (type,callback){
    //当emit时warp执行需要继续将参数传递给callback
    let warp = (...args) =>{
        callback(...args);
        this.removeListener(type,warp) //用on绑定的时候,在emit的时候执行wap
    }
    warp.l = callback;//将callback方法挂在到warp属性上
    this.on(type,warp);
}
//在once包了一层wap,我们需要对此wap做细节处理

复制代码

emit

EventEmitter.prototype.emit = function(type , ...args){
    if(this._events[type]){
        this._events[type].forEach(fn => fn(...args));
    }else{
        this._events = {}
    }
}
//找到数组里的方法对应的移除掉即可
EventEmitter.prototype.removeListener = function(type,callback){
    if (typeof callback !== 'function')  throw new TypeError('"callback" argument must be a function');
    if(this._events[type]){
        // filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
        //this._events[type] = this._events[type].filter(fn =>{
        //     return fn != callback && fn.l != callback
        // })
        //一次只删除一个,不是删除所有相同的type,应该用下面方法
        for(let i = 0;i < this._events[type].length;i++){
            if(this._events[type][i] == callback || this._events[type][i].l == callback ){
                this._events[type].splice[i]
                break;
            }
        }
        //不考虑warp同上效果
        //this._events[type].splice(this._events[type].indexOf(callback) ,1)
    }
}
复制代码

所以现在我们写出的代码总结如下

function EventEmitter(){
    this._events = {}
}
//this._events = {one:[cry],two:[drink]}
EventEmitter.prototype.eventNames = function(){
    return Object.keys(this._events)
}
EventEmitter.prototype.listeners = function(type){
    return this._events[type]
}

EventEmitter.defaultMaxListeners = 10; //默认最大监听数
EventEmitter.prototype.setMaxListeners = function(count){
    this._count = count;
}
EventEmitter.prototype.getMaxListeners = function(){
    return  this._count || EventEmitter.defaultMaxListeners
}

EventEmitter.addListener = EventEmitter.prototype.on = function(type,callback){
    //如果实例不存在则会创建一个空对象
    if(!this._events)  this._events = Object.create(null) //继承会找不到event ,直接实例可以, Cannot read property 'one' of undefined 初始化this._events
    // this._events ={}  和 this._events = Object.create(null) 的区别 前者原型指针指向object链,后者没有任何属性,后者可以避免第三方继承
    //如果当前不是newListenernewListener方法就需要让newListener回调一次执行,传入类
    if(this.newListener && this._events['newListener'] && this._events['newListener'].length>0){
        if(type != 'newListener'){
            this._events['newListener'].forEach(fn => fn(type))
        }
    }
    if(this._events[type]){ // 查看事件名称是否存在
        this._events[type].push(callback)
    }else{
        this._events[type] = [callback] //将事件绑定在对象上
    }
    if(this._events[type].length === this.getMaxListeners()){
        console.warn('memeoy link detected')
    }
}

EventEmitter.prototype.emit = function(type , ...args){
    if(this._events[type]){
        this._events[type].forEach(fn => fn(...args));
    }else{
        this._events = {}
    }
}
//找到数组里的方法对应的移除掉即可
EventEmitter.prototype.removeListener = function(type,callback){
    if (typeof callback !== 'function')  throw new TypeError('"callback" argument must be a function');
    if(this._events[type]){
        // filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
        //this._events[type] = this._events[type].filter(fn =>{
        //     fn != callback && fn.l != callback
        // })
        //一次只删除一个,不是删除所有相同的type,应该用下面方法
        for(let i = 0;i < this._events[type].length;i++){
            if(this._events[type][i] == callback || this._events[type][i].l == callback ){
                this._events[type].splice[i]
                break;
            }
        }
        //不考虑warp同上效果
        //this._events[type].splice(this._events[type].indexOf(callback) ,1)
    }
}
EventEmitter.prototype.removeAllListeners = function(type){
    if(this._events[type]){
        return this._events[type] = Obj.create(null)
    }else{

    }
}
EventEmitter.prototype.once = function (type,callback){
    //当emit时warp执行需要继续将参数传递给callback
    let warp = (...args) =>{
        callback(...args);
        this.removeListener(type,warp) //用on绑定的时候,在emit的时候执行wap
    }
    warp.l = callback;//将callback方法挂在到warp属性上
    this.on(type,warp);
}

module.exports = EventEmitter;
复制代码

测试代码

//发布订阅模式
//将时间放到数组中,当真的发生时在执行

// let  EventEmitter = require('events');
let  EventEmitter = require('./EventEmitter');
let {inherits} = require('util');
function Girl(){
}
inherits(Girl,EventEmitter);
let girl = new Girl;
let cry = (a,b,c) =>{
    console.log('cry',a,b,c)
}
let drink = () =>{
    console.log('drink')
}

girl.on('newListener',(type) => {
    console.log(type)
})
girl.on('one',cry)
girl.on('one',drink)
girl.on('one',cry)


girl.removeListener('one',cry) //找到one把 事件删掉

girl.emit('one',1,2,3);
console.log(girl.eventNames())
console.log(girl.listeners('one'))
复制代码

util使用

我们经常用的util模块(node 8版本以上)

let {promisify,inherits} = require('util');
let fs = require('fs');

let read = promisify(fs.readFile); //
read('1.txt','utf8').then(data =>{
    console.log(data)
})
//相当于
async function r(){
    try{  
        let result = await read('1.txt','utf8')
        return result;
    }catch(e){
        throw e;
    }
}
r().then(data=>{
    console.log(data)
},err=>{console.log(err)})
//koa 后期也是采用 async await

function A(){

}
A.prototype.a = 1;
function B(){

}
inherits(B,A)//b继承a 之继承公有方法
let b = new B()
console.log(b.a);
//相当于
B.prototype = Object.create(A.prototype)
//相当于
B.prototype.__proto__ = A.prototype
//相当于
Object.setPrototypeOf(B.prototype,A.prototype)


原文发布时间为:2018年06月28日
原文作者:dlzhao
本文来源: 掘金  如需转载请联系原作者
相关文章
|
1月前
|
JavaScript 前端开发
Node.js中的EventEmitter模块:基本概念、使用方法和常见应用场景
Node.js中的EventEmitter模块:基本概念、使用方法和常见应用场景
70 0
|
18天前
|
JavaScript 前端开发 索引
Node.js EventEmitter
Node.js EventEmitter
10 1
|
JSON 缓存 JavaScript
Node.js EventEmitter 和 Buffer
Node.js EventEmitter 和 Buffer
|
JavaScript 前端开发 应用服务中间件
实战Node.js原理对于阻塞和EventEmitter及其继承的运用心得
实战Node.js原理对于阻塞和EventEmitter及其继承的运用心得
实战Node.js原理对于阻塞和EventEmitter及其继承的运用心得
|
JSON JavaScript 数据格式
Node.js躬行记(1)——Buffer、流和EventEmitter
  Buffer是一种Node的内置类型,不需要通过require()函数额外引入。它能读取和写入二进制数据,常用于解析网络数据流、文件等。
|
JavaScript
Node.js EventEmitter
Node.js EventEmitter Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。 Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。
1276 0
|
JavaScript
Node.js EventEmitter (触发器)
Node.js EventEmitter Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列. Node.js里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。
789 0