Once Handling in EventEmitter

· 1 min read

EventEmitter Initial Version

class EventEmitter{

    constructor(){
        this.events={}
    }

    on(type,listener){
       if(!this.events[type]){
        this.events[type]=[]
       }
       this.events[type].push(listener)
    }


    emit(type,...args){
        this.events[type].forEach(listener=>{
            listener.call(this,...args)
        })
    }

    off(type,listener){
        if(this.events[type]){
            const index=this.events[type].indexOf(listener)
            if(index!==-1){
                this.events[type].splice(index,1)
            }
        }
    }


    once(type,listener){
        const onceListener=(...args)=>{
            listener.call(this,...args)
            this.off(type,onceListener)
        }
        this.on(type,onceListener)
    }
}

Testing

const eventEmitter=new EventEmitter()
const listener=(args)=>{
    console.log(args);
}
eventEmitter.once('test',listener)
eventEmitter.off('test',listener)
eventEmitter.emit('test',{a:1})

When executing the above code, you’ll find that the test event was triggered once, but it should not execute because it was turned off. The solution is as follows.

Once Failure

...
 off(type,listener){
        if(this.events[type]){
            const index=this.events[type].findIndex(l=>l.fn===listener||l===listener)
            if(index!==-1){
                this.events[type].splice(index,1)
            }
        }
    }

... 

 once(type,listener){
        const onceListener=(...args)=>{
            listener.call(this,...args)
            this.off(type,onceListener)
        }
        onceListener.fn=listener
        this.on(type,onceListener)
    }

Final Thoughts

Read more source code