Skip to content

Emitter

Emitter<T> (from scenerystack/axon) is a typed event bus for discrete occurrences that carry no persistent state — a reset button being pressed, a collision happening, a level being completed. Unlike Property, an Emitter has no "current value": a newly-added listener does not get called back with anything, it only hears about events that happen after it subscribes.

ts
import { Emitter } from 'scenerystack/axon';

const resetEmitter = new Emitter();

resetEmitter.addListener( () => console.log( 'sim was reset' ) );
resetEmitter.emit(); // logs "sim was reset"

Typed parameters

Emitter<T extends TEmitterParameter[] = []> is generic over the tuple of arguments passed to emit(). Declare the parameter types as a tuple:

ts
const scoredEmitter = new Emitter<[ points: number, isBonus: boolean ]>();

scoredEmitter.addListener( ( points, isBonus ) => {
  console.log( `scored ${points} points${isBonus ? ' (bonus!)' : ''}` );
} );

scoredEmitter.emit( 10, false );

Methods

MethodEffect
emit( ...args )Calls every listener synchronously with args
addListener( listener )Registers a listener to be called on emit()
removeListener( listener )Removes a specific listener
removeAllListeners()Removes every listener
hasListener( listener )Checks whether a listener is registered
hasListeners()Whether any listener is registered
getListenerCount()Number of registered listeners
dispose()Removes all listeners; call this when the Emitter's owner is disposed

Options

EmitterOptions is mostly PhET-iO metadata (tandem, phetioDocumentation, parameters describing each argument for the data stream) plus two low-level tuning knobs inherited from TinyEmitter:

OptionEffect
reentrantNotificationStrategy'stack' (default) or 'queue' — controls ordering when a listener triggers another emit() of the same Emitter while still notifying
disableListenerLimitDisables the dev-mode assertion that catches an unbounded number of listeners (a common memory-leak symptom)
ts
const explodedEmitter = new Emitter( {
  reentrantNotificationStrategy: 'queue'
} );

Emitter vs. Property

If what you're modeling has a "current value" that late-arriving listeners should immediately see — visibility, a numeric setting, a mode — use Property (or a typed subclass). Reach for Emitter only for momentary occurrences with no meaningful "current state." See Emitter vs. Property for more on making this call. createObservableArray uses Emitters internally (elementAddedEmitter, elementRemovedEmitter) as a good worked example of the distinction — the array's contents are state (its lengthProperty), but each add/remove is a discrete event.