Skip to content

events: pass the original listener added by EventEmitter#once to the removeListener handler

Checklist
  • tests and code linting passes
  • the commit message follows commit guidelines
  • a test and/or benchmark is included
Description of change

We use the _onceWrap function to wrap the listener added by EventEmitter#once, and use the flag fired inside to make sure the listener will only be called once, including the calling in the removeListener event:

'use strict'
const EventEmitter = require('events')

let ee = new EventEmitter()

ee.once('test', () => console.log('test'))

ee.on('removeListener', (eventName, listener) => {
  console.log(`eventName: ${eventName}`)
  listener.call(ee)
  listener.call(ee)
  listener.call(ee)
})

ee.emit('test')
// eventName: test
// test

But by explicitly invoking the listener in the removeListener handler the user expresses a pretty strong intent that the listener should be called. By now we can use a listener.listener trick to archive this:

'use strict'
const EventEmitter = require('events')

let ee = new EventEmitter()

ee.once('test', () => console.log('test'))

ee.on('removeListener', (eventName, listener) => {
  console.log(`eventName: ${eventName}`)
  listener.listener.call(ee)
  listener.listener.call(ee)
  listener.listener.call(ee)
})

ee.emit('test')
// eventName: test
// test
// test
// test
// test

But those who have not read the the code of lib/events.js should not know this trick at all, and using tricks is alway not a good way. so this PR is to pass the original listener added by EventEmitter#once to the removeListener handler:

'use strict'
const EventEmitter = require('events')

let ee = new EventEmitter()

ee.once('test', () => console.log('test'))

ee.on('removeListener', (eventName, listener) => {
  console.log(`eventName: ${eventName}`)
  listener()
  listener()
  listener()
})

ee.emit('test')
// eventName: test
// test
// test
// test
// test

Merge request reports

Loading