包详细信息

@universal-packages/event-emitter

universal-packages38.5kMIT2.2.1

Event emitter 2 universal convention

自述文件

Event Emitter

npm version Testing codecov

Rich emitted event event emitter with typescript support.

Getting Started

npm install @universal-packages/event-emitter

Usage

EventEmitter class

Just instantiate the class and start emitting events.

import { EventEmitter } from '@universal-packages/event-emitter'

const emitter = new EventEmitter()

emitter.on('event', (event) => {
  console.log(event)
})

emitter.emit('event', { payload: { foo: 'bar' } })
emitter.emit('error', { error: new Error('Something went wrong') })

Constructor constructor

new EventEmitter(options?: EventEmitterOptions)

Creates a new EventEmitter instance.

Options

  • delimiter String default: ':' The delimiter to use for event names.

  • maxListeners Number default: 20 The maximum number of listeners for an event before start considering it a memory leak.

  • useWildcards Boolean default: true Whether to use wildcards for event names. ex: 'user:* or even * for all events.

  • newListenerEvent Boolean default: true Whether to emit a new listener event when a listener is added.

  • removeListenerEvent Boolean default: false Whether to emit a remove listener event when a listener is removed.

  • verboseMemoryLeak Boolean default: true Whether to log memory leaks (when a listener is added after the maxListeners limit is reached).

  • ignoreErrors Boolean default: true If false when emitting an error and no error listener is added the error will be thrown.

Getters/Setters

maxListeners

emitter.maxListeners

Returns the maximum number of listeners for an event before start considering it a memory leak.

eventNames

emitter.eventNames

Returns the event names that the emitter is listening to.

listenerCount

emitter.listenerCount

Returns the number of listeners for a given event.

listeners

emitter.listeners

Returns the listeners for a given event.

Instance Methods

emit

emitter.emit(eventName: string | string[], event?: EventIn): boolean

Emits an event for the given event name or names. Or even wildcards.

// All event listeners that start with user like user:created, user:updated, user:deleted
emitter.emit('user:*', { payload: { foo: 'bar' } })

// All event listeners will receive the event
emitter.emit('*', { payload: { foo: 'bar' } })

// Specific event, just the user:created listeners will receive the event
emitter.emit('user:created', { payload: { foo: 'bar' } })
EventIn

The event object that is passed to the listener. It is packed with common and useful properties.

  • error Error optional This can be set with the error event but you can also set errors for any reason you want.

    emitter.emit('task:done', { error: new Error('Something went wrong'), message: 'Task partially done, but with error' })
    
  • measurement Measurement optional You may want processes to be measured. And share that when emitting an event.

    import { TimeMeasurer } from '@universal-packages/time-measurer'
    
    const measurer = TimeMeasurer.start()
    emitter.emit('task:done', { measurement: measurer.finish(), message: 'Task done' })
    
  • message String optional A concise message to share with the listeners.

  • payload T optional When the EventEmitter is event typed (a predefine number of event names and its payloads are defined) you set this to that predefine shape, other wise you can set any payload you want.

    emitter.emit('task:done', { payload: { foo: 'bar' } })
    emitter.emit('task:done', { payload: 66 })
    

emitAsync

emitter.emitAsync(eventName: string | string[], event?: EventIn): Promise<any[]>

Emits an event asynchronously returning a promise that resolves when all listeners are done.

addListener

emitter.addListener(eventName: string | string[], listener: ListenerFn): this

Adds a listener for a given event or events.

// Will be called when the event "event" is emitted
emitter.addListener('event', (event) => {
  console.log(event)
})

// Will be called when one level event is emitted
emitter.addListener('*', (event) => {
  console.log(event)
})

// Will be called when two levels event is emitted
emitter.addListener('*:*', (event) => {
  console.log(event)
})

// Will be called for all events
emitter.addListener('**', (event) => {
  console.log(event)
})

// Will be called when any 2event that starts with "user:" is emitted
emitter.addListener('user:*', (event) => {
  console.log(event)
})

// Will be called when any event that starts with "user:" is emitted
emitter.addListener('user:**', (event) => {
  console.log(event)
})

// Will be called when the event "users:created" or "users:updated" are emitted
emitter.addListener(['users:created', 'users:updated'], (event) => {
  console.log(event)
})

// Will be called when the event any of the 2 level events that start with "users:" or "tasks:" are emitted
emitter.addListener(['users:*', 'tasks:*'], (event) => {
  console.log(event)
})
ListenerFn
(event?: EmittedEvent<TPayload>): void | Promise<void>

The listener function that is called when an event is emitted. It receives all that was emitted in the #EventIn, for types events, the payload will be the shape it was types for the event.

on

emitter.on(eventName: string | string[], listener: ListenerFn): this

Adds a listener for a given event just like addListener,

emitter.on('event', (event) => {
  console.log(event)
})

prependListener

emitter.on(eventName: string | string[], listener: ListenerFn): this

Adds a listener for a given event just like addListener, but the listener will be called before the other listeners.

emitter.prependListener('event', (event) => {
  console.log(event)
})

once

emitter.once(eventName: string | string[], listener: ListenerFn): this

Adds a listener for a given event just like addListener, but the listener will be called only once.

emitter.once('event', (event) => {
  console.log(event)
})

prependOnceListener

emitter.prependOnceListener(eventName: string | string[], listener: ListenerFn): this

Adds a listener for a given event just like once, but the listener will be called before the other listeners.

emitter.prependOnceListener('event', (event) => {
  console.log(event)
})

removeListener

emitter.removeListener(eventName: string | string[], listener: ListenerFn): this

Removes a listener for a given event or events.

// Will remove the listeners for the event "event" only
emitter.removeListener('event', (event) => {
  console.log(event)
})

// Will remove the listeners for the events "users:created" and "users:updated"
emitter.removeListener(['users:created', 'users:updated'], (event) => {
  console.log(event)
})

off

emitter.off(eventName: string | string[], listener: ListenerFn): this

Removes a listener for a given event or events.

removeAllListeners

emitter.removeAllListeners(eventName?: string | string[]): this

Removes all listeners for a given event or events.

// Will remove all listeners for the event "event"
emitter.removeAllListeners('event')

waitFor

emitter.waitFor(eventName: string): CancelablePromise<EmittedEvent<TPayload>[]>

Waits for a given event to be emitted, it returns a cancelable promise that resolves with the emitted event.

const promise = emitter.waitFor('event')

promise.then((event) => {
  console.log(event)
})

hasListeners

emitter.hasListeners(eventName: string | string[]): Boolean

Returns true if there are listeners for a given event or events.

// Will return true if there are listeners for the event "event"
emitter.hasListeners('event')

Type-Safe Events

This library provides full TypeScript support with generic event types. You can define your event names and their payload types for complete type safety:

import { EventEmitter } from '@universal-packages/event-emitter'

// Define your event map
interface MyEvents {
  'user:created': { id: string; name: string }
  'user:updated': { id: string; changes: Record<string, any> }
  numbers: number[]
  message: string
}

// Create a typed event emitter
const emitter = new EventEmitter<MyEvents>()

// TypeScript provides autocompletion for event names
emitter.on('user:created', (event) => {
  // event.payload is typed as { id: string; name: string }
  console.log(`User created: ${event.payload.id}, ${event.payload.name}`)
})

// Emit with type checking
emitter.emit('user:created', {
  payload: {
    id: '123',
    name: 'John'
  }
})

// TypeScript will catch type errors:
// emitter.emit('user:created', { payload: { id: 123 } }) // Error: Type 'number' is not assignable to type 'string'
// emitter.emit('user:created', { payload: {}) // Error: Type '{}' is not assignable to type '{ id: string; name: string; }'

Mixed Typed and Dynamic Events

You can use both typed and dynamic events in the same emitter:

// Use your typed events with autocompletion
emitter.on('user:created', (event) => {
  // Fully typed payload
  const id: string = event.payload.id
})

// Use dynamic events when needed
emitter.on('custom:event', (event: EmittedEvent<{ custom: boolean }>) => {
  // Dynamic payload
  console.log(event.payload)
})

// Use wildcards
emitter.onAny((eventName, event) => {
  console.log(`Event fired: ${eventName}`)
})

Typescript

This library is developed in TypeScript and shipped fully typed.

Contributing

The development of this library happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving this library.

License

MIT licensed.