eventemitter2
Advanced tools
Comparing version 6.3.1 to 6.4.0
@@ -9,2 +9,19 @@ # Change Log | ||
## [6.4.0] - 2020-05-04 | ||
### Added | ||
- Symbol events support for simple and wildcard emitters #201 @DigitalBrainJS | ||
- `emitter.hasListeners` method #251 @DigitalBrainJS | ||
- `emitter.listenTo` & `emitter.stopListeningTo` methods for listening to an external event emitter of any kind and propagate its events through itself using optional reducers/filters @DigitalBrainJS | ||
- async listeners for invoking handlers using setImmediate|setTimeout|nextTick (see `async`, `promisify` and `nextTicks` options for subscription methods) @DigitalBrainJS | ||
- Ability for subscription methods to return a listener object to simplify subscription management (see the `objectify` option) @DigitalBrainJS | ||
- micro optimizations for performance reasons @DigitalBrainJS | ||
### Fixed | ||
- Event name/reference normalization for the `this.event` property #162 @DigitalBrainJS | ||
- Bug with data arguments for `Any` listeners #254 @DigitalBrainJS | ||
- `emitter.eventNames` now supports wildcard emitters #214 @DigitalBrainJS | ||
## [6.3.0] - 2020-03-28 | ||
@@ -14,3 +31,3 @@ | ||
- emitter.getMaxListeners() & EventEmitter2.defaultMaxListeners() @DigitalBrainJS | ||
- EventEmitter2.once for feature pairity with EventEmitter.once @DigitalBrainJS | ||
- EventEmitter2.once for feature parity with EventEmitter.once @DigitalBrainJS | ||
@@ -17,0 +34,0 @@ ## [6.2.1] - 2020-03-20 |
@@ -1,2 +0,4 @@ | ||
export type eventNS = string[]; | ||
export type event = (symbol|string); | ||
export type eventNS = string|event[]; | ||
export interface ConstructorOptions { | ||
@@ -39,3 +41,3 @@ /** | ||
} | ||
export interface Listener { | ||
export interface ListenerFn { | ||
(...values: any[]): void; | ||
@@ -91,29 +93,60 @@ } | ||
export interface ListenToOptions { | ||
on?: { (event: event | eventNS, handler: Function): void }, | ||
off?: { (event: event | eventNS, handler: Function): void }, | ||
reducers: Function | Object | ||
} | ||
export interface GeneralEventEmitter{ | ||
addEventListener: Function, | ||
removeEventListener: Function | ||
} | ||
export interface OnOptions { | ||
async?: boolean, | ||
promisify?: boolean, | ||
nextTick?: boolean, | ||
objectify?: boolean | ||
} | ||
export interface Listener { | ||
emitter: EventEmitter2; | ||
event: event|eventNS; | ||
listener: ListenerFn; | ||
off(): this; | ||
} | ||
export declare class EventEmitter2 { | ||
constructor(options?: ConstructorOptions) | ||
emit(event: string | string[], ...values: any[]): boolean; | ||
emitAsync(event: string | string[], ...values: any[]): Promise<any[]>; | ||
addListener(event: string, listener: Listener): this; | ||
on(event: string | string[], listener: Listener): this; | ||
prependListener(event: string | string[], listener: Listener): this; | ||
once(event: string | string[], listener: Listener): this; | ||
prependOnceListener(event: string | string[], listener: Listener): this; | ||
many(event: string | string[], timesToListen: number, listener: Listener): this; | ||
prependMany(event: string | string[], timesToListen: number, listener: Listener): this; | ||
emit(event: event | eventNS, ...values: any[]): boolean; | ||
emitAsync(event: event | eventNS, ...values: any[]): Promise<any[]>; | ||
addListener(event: event | eventNS, listener: ListenerFn): this|Listener; | ||
on(event: event | eventNS, listener: ListenerFn, options?: boolean|OnOptions): this|Listener; | ||
prependListener(event: event | eventNS, listener: ListenerFn, options?: boolean|OnOptions): this|Listener; | ||
once(event: event | eventNS, listener: ListenerFn, options?: true|OnOptions): this|Listener; | ||
prependOnceListener(event: event | eventNS, listener: ListenerFn, options?: boolean|OnOptions): this|Listener; | ||
many(event: event | eventNS, timesToListen: number, listener: ListenerFn, options?: boolean|OnOptions): this|Listener; | ||
prependMany(event: event | eventNS, timesToListen: number, listener: ListenerFn, options?: boolean|OnOptions): this|Listener; | ||
onAny(listener: EventAndListener): this; | ||
prependAny(listener: EventAndListener): this; | ||
offAny(listener: Listener): this; | ||
removeListener(event: string | string[], listener: Listener): this; | ||
off(event: string, listener: Listener): this; | ||
removeAllListeners(event?: string | eventNS): this; | ||
offAny(listener: ListenerFn): this; | ||
removeListener(event: event | eventNS, listener: ListenerFn): this; | ||
off(event: event | eventNS, listener: ListenerFn): this; | ||
removeAllListeners(event?: event | eventNS): this; | ||
setMaxListeners(n: number): void; | ||
getMaxListeners(): number; | ||
eventNames(): string[]; | ||
listeners(event: string | string[]): Listener[] | ||
listenersAny(): Listener[] // TODO: not in documentation by Willian | ||
waitFor(event: string, timeout?: number): CancelablePromise<any[]> | ||
waitFor(event: string, filter?: WaitForFilter): CancelablePromise<any[]> | ||
waitFor(event: string, options?: WaitForOptions): CancelablePromise<any[]> | ||
static once(emitter: EventEmitter2, event: string | symbol, options?: OnceOptions): CancelablePromise<any[]> | ||
eventNames(nsAsArray?: boolean): (event|eventNS)[]; | ||
listenerCount(event?: event | eventNS): number | ||
listeners(event?: event | eventNS): ListenerFn[] | ||
listenersAny(): ListenerFn[] | ||
waitFor(event: event | eventNS, timeout?: number): CancelablePromise<any[]> | ||
waitFor(event: event | eventNS, filter?: WaitForFilter): CancelablePromise<any[]> | ||
waitFor(event: event | eventNS, options?: WaitForOptions): CancelablePromise<any[]> | ||
listenTo(target: GeneralEventEmitter, events: event | eventNS, options?: ListenToOptions): this; | ||
listenTo(target: GeneralEventEmitter, events: event[], options?: ListenToOptions): this; | ||
listenTo(target: GeneralEventEmitter, events: Object, options?: ListenToOptions): this; | ||
stopListeningTo(target?: GeneralEventEmitter, event?: event | eventNS): Boolean; | ||
hasListeners(event?: String): Boolean | ||
static once(emitter: EventEmitter2, event: event | eventNS, options?: OnceOptions): CancelablePromise<any[]>; | ||
static defaultMaxListeners: number; | ||
} |
@@ -14,2 +14,12 @@ /*! | ||
var defaultMaxListeners = 10; | ||
var nextTickSupported= typeof process=='object' && typeof process.nextTick=='function'; | ||
var symbolsSupported= typeof Symbol==='function'; | ||
var reflectSupported= typeof Reflect === 'object'; | ||
var setImmediateSupported= typeof setImmediate === 'function'; | ||
var _setImmediate= setImmediateSupported ? setImmediate : setTimeout; | ||
var ownKeys= symbolsSupported? (reflectSupported && typeof Reflect.ownKeys==='function'? Reflect.ownKeys : function(obj){ | ||
var arr= Object.getOwnPropertyNames(obj); | ||
arr.push.apply(arr, Object.getOwnPropertySymbols(obj)); | ||
return arr; | ||
}) : Object.keys; | ||
@@ -89,6 +99,169 @@ function init() { | ||
function toObject(keys, values) { | ||
var obj = {}; | ||
var key; | ||
var len = keys.length; | ||
var valuesCount = values ? value.length : 0; | ||
for (var i = 0; i < len; i++) { | ||
key = keys[i]; | ||
obj[key] = i < valuesCount ? values[i] : undefined; | ||
} | ||
return obj; | ||
} | ||
function TargetObserver(emitter, target, options) { | ||
this._emitter = emitter; | ||
this._target = target; | ||
this._listeners = {}; | ||
this._listenersCount = 0; | ||
var on, off; | ||
if (options.on || options.off) { | ||
on = options.on; | ||
off = options.off; | ||
} | ||
if (target.addEventListener) { | ||
on = target.addEventListener; | ||
off = target.removeEventListener; | ||
} else if (target.addListener) { | ||
on = target.addListener; | ||
off = target.removeListener; | ||
} else if (target.on) { | ||
on = target.on; | ||
off = target.off; | ||
} | ||
if (!on && !off) { | ||
throw Error('target does not implement any known event API'); | ||
} | ||
if (typeof on !== 'function') { | ||
throw TypeError('on method must be a function'); | ||
} | ||
if (typeof off !== 'function') { | ||
throw TypeError('off method must be a function'); | ||
} | ||
this._on = on; | ||
this._off = off; | ||
var _observers= emitter._observers; | ||
if(_observers){ | ||
_observers.push(this); | ||
}else{ | ||
emitter._observers= [this]; | ||
} | ||
} | ||
Object.assign(TargetObserver.prototype, { | ||
subscribe: function(event, localEvent, reducer){ | ||
var observer= this; | ||
var target= this._target; | ||
var emitter= this._emitter; | ||
var listeners= this._listeners; | ||
var handler= function(){ | ||
var args= toArray.apply(null, arguments); | ||
var eventObj= { | ||
data: args, | ||
name: localEvent, | ||
original: event | ||
}; | ||
if(reducer){ | ||
var result= reducer.call(target, eventObj); | ||
if(result!==false){ | ||
emitter.emit.apply(emitter, [eventObj.name].concat(args)) | ||
} | ||
return; | ||
} | ||
emitter.emit.apply(emitter, [localEvent].concat(args)); | ||
}; | ||
if(listeners[event]){ | ||
throw Error('Event \'' + event + '\' is already listening'); | ||
} | ||
this._listenersCount++; | ||
if(emitter._newListener && emitter._removeListener && !observer._onNewListener){ | ||
this._onNewListener = function (_event) { | ||
if (_event === localEvent && listeners[event] === null) { | ||
listeners[event] = handler; | ||
observer._on.call(target, event, handler); | ||
} | ||
}; | ||
emitter.on('newListener', this._onNewListener); | ||
this._onRemoveListener= function(_event){ | ||
if(_event === localEvent && !emitter.hasListeners(_event) && listeners[event]){ | ||
listeners[event]= null; | ||
observer._off.call(target, event, handler); | ||
} | ||
}; | ||
listeners[event]= null; | ||
emitter.on('removeListener', this._onRemoveListener); | ||
}else{ | ||
listeners[event]= handler; | ||
observer._on.call(target, event, handler); | ||
} | ||
}, | ||
unsubscribe: function(event){ | ||
var observer= this; | ||
var listeners= this._listeners; | ||
var emitter= this._emitter; | ||
var handler; | ||
var events; | ||
var off= this._off; | ||
var target= this._target; | ||
var i; | ||
if(event && typeof event!=='string'){ | ||
throw TypeError('event must be a string'); | ||
} | ||
function clearRefs(){ | ||
if(observer._onNewListener){ | ||
emitter.off('newListener', observer._onNewListener); | ||
emitter.off('removeListener', observer._onRemoveListener); | ||
observer._onNewListener= null; | ||
observer._onRemoveListener= null; | ||
} | ||
var index= findTargetIndex.call(emitter, observer); | ||
emitter._observers.splice(index, 1); | ||
} | ||
if(event){ | ||
handler= listeners[event]; | ||
if(!handler) return; | ||
off.call(target, event, handler); | ||
delete listeners[event]; | ||
if(!--this._listenersCount){ | ||
clearRefs(); | ||
} | ||
}else{ | ||
events= ownKeys(listeners); | ||
i= events.length; | ||
while(i-->0){ | ||
event= events[i]; | ||
off.call(target, event, listeners[event]); | ||
} | ||
this._listeners= {}; | ||
this._listenersCount= 0; | ||
clearRefs(); | ||
} | ||
} | ||
}); | ||
function resolveOptions(options, schema, reducers, allowUnknown) { | ||
var computedOptions = Object.assign({}, schema); | ||
if(!options) return computedOptions; | ||
if (!options) return computedOptions; | ||
@@ -104,5 +277,6 @@ if (typeof options !== 'object') { | ||
function reject(reason){ | ||
throw Error('Invalid "' + option + '" option value' + (reason? '. Reason: '+ reason : '')) | ||
function reject(reason) { | ||
throw Error('Invalid "' + option + '" option value' + (reason ? '. Reason: ' + reason : '')) | ||
} | ||
for (var i = 0; i < length; i++) { | ||
@@ -124,3 +298,3 @@ option = keys[i]; | ||
if (typeof value !== 'function' || !value.hasOwnProperty('prototype')) { | ||
reject('Promise option must be a constructor'); | ||
reject('value must be a constructor'); | ||
} | ||
@@ -130,9 +304,17 @@ return value; | ||
function functionReducer(value, reject) { | ||
if (typeof value !== 'function') { | ||
reject('Promise option must be a function'); | ||
} | ||
return value; | ||
function makeTypeReducer(types) { | ||
var message= 'value must be type of ' + types.join('|'); | ||
var conditions= types.map(function(type){ | ||
return 'a==="'+ type.toLowerCase()+'"'; | ||
}).join('||'); | ||
return new Function( | ||
'm', | ||
'return function(v, reject){var a= typeof v;if(!('+ conditions + '))reject(m);return v;}' | ||
)(message); | ||
} | ||
var functionReducer= makeTypeReducer(['function']); | ||
var objectFunctionReducer= makeTypeReducer(['object', 'function']); | ||
function makeCancelablePromise(Promise, executor, options) { | ||
@@ -226,12 +408,14 @@ var isCancelable; | ||
function EventEmitter(conf) { | ||
this._events = {}; | ||
this._newListener = false; | ||
this._removeListener = false; | ||
this.verboseMemoryLeak = false; | ||
configure.call(this, conf); | ||
function findTargetIndex(observer) { | ||
var observers = this._observers; | ||
if(!observers){ | ||
return -1; | ||
} | ||
var len = observers.length; | ||
for (var i = 0; i < len; i++) { | ||
if (observers[i]._target === observer) return i; | ||
} | ||
return -1; | ||
} | ||
EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property | ||
// | ||
// Attention, function return type now is array, always ! | ||
@@ -354,4 +538,4 @@ // It has zero elements if no any matches found and one or more | ||
// | ||
for(var i = 0, len = type.length; i+1 < len; i++) { | ||
if(type[i] === '**' && type[i+1] === '**') { | ||
for (var i = 0, len = type.length; i + 1 < len; i++) { | ||
if (type[i] === '**' && type[i + 1] === '**') { | ||
return; | ||
@@ -376,4 +560,3 @@ } | ||
tree._listeners = listener; | ||
} | ||
else { | ||
} else { | ||
if (typeof tree._listeners === 'function') { | ||
@@ -386,5 +569,5 @@ tree._listeners = [tree._listeners]; | ||
if ( | ||
!tree._listeners.warned && | ||
this._maxListeners > 0 && | ||
tree._listeners.length > this._maxListeners | ||
!tree._listeners.warned && | ||
this._maxListeners > 0 && | ||
tree._listeners.length > this._maxListeners | ||
) { | ||
@@ -402,2 +585,202 @@ tree._listeners.warned = true; | ||
function collectTreeEvents(tree, events, root, asArray){ | ||
var branches= ownKeys(tree); | ||
var i= branches.length; | ||
var branch, branchName, path; | ||
var hasListeners= tree['_listeners']; | ||
var isArrayPath; | ||
while(i-->0){ | ||
branchName= branches[i]; | ||
branch= tree[branchName]; | ||
if(branchName==='_listeners'){ | ||
path= root; | ||
}else { | ||
path = root ? root.concat(branchName) : [branchName]; | ||
} | ||
isArrayPath= asArray || typeof branchName==='symbol'; | ||
hasListeners && events.push(isArrayPath? path : path.join(this.delimiter)); | ||
if(typeof branch==='object'){ | ||
collectTreeEvents.call(this, branch, events, path, isArrayPath); | ||
} | ||
} | ||
return events; | ||
} | ||
function recursivelyGarbageCollect(root) { | ||
var keys = ownKeys(root); | ||
var i= keys.length; | ||
var obj, key, flag; | ||
while(i-->0){ | ||
key = keys[i]; | ||
obj = root[key]; | ||
if(obj){ | ||
flag= true; | ||
if(key !== '_listeners' && !recursivelyGarbageCollect(obj)){ | ||
delete root[key]; | ||
} | ||
} | ||
} | ||
return flag; | ||
} | ||
function Listener(emitter, event, listener){ | ||
this.emitter= emitter; | ||
this.event= event; | ||
this.listener= listener; | ||
} | ||
Listener.prototype.off= function(){ | ||
this.emitter.off(this.event, this.listener); | ||
return this; | ||
}; | ||
function setupListener(event, listener, options){ | ||
if (options === true) { | ||
promisify = true; | ||
} else if (options === false) { | ||
async = true; | ||
} else { | ||
if (!options || typeof options !== 'object') { | ||
throw TypeError('options should be an object or true'); | ||
} | ||
var async = options.async; | ||
var promisify = options.promisify; | ||
var nextTick = options.nextTick; | ||
var objectify = options.objectify; | ||
} | ||
if (async || nextTick || promisify) { | ||
var _listener = listener; | ||
var _origin = listener._origin || listener; | ||
if (nextTick && !nextTickSupported) { | ||
throw Error('process.nextTick is not supported'); | ||
} | ||
if (promisify === undefined) { | ||
promisify = listener.constructor.name === 'AsyncFunction'; | ||
} | ||
listener = function () { | ||
var args = arguments; | ||
var context = this; | ||
var event = this.event; | ||
return promisify ? (nextTick ? Promise.resolve() : new Promise(function (resolve) { | ||
_setImmediate(resolve); | ||
}).then(function () { | ||
context.event = event; | ||
return _listener.apply(context, args) | ||
})) : (nextTick ? process.nextTick : _setImmediate)(function () { | ||
context.event = event; | ||
_listener.apply(context, args) | ||
}); | ||
}; | ||
listener._async = true; | ||
listener._origin = _origin; | ||
} | ||
return [listener, objectify? new Listener(this, event, listener): this]; | ||
} | ||
function EventEmitter(conf) { | ||
this._events = {}; | ||
this._newListener = false; | ||
this._removeListener = false; | ||
this.verboseMemoryLeak = false; | ||
configure.call(this, conf); | ||
} | ||
EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property | ||
EventEmitter.prototype.listenTo= function(target, events, options){ | ||
if(typeof target!=='object'){ | ||
throw TypeError('target musts be an object'); | ||
} | ||
var emitter= this; | ||
options = resolveOptions(options, { | ||
on: undefined, | ||
off: undefined, | ||
reducers: undefined | ||
}, { | ||
on: functionReducer, | ||
off: functionReducer, | ||
reducers: objectFunctionReducer | ||
}); | ||
function listen(events){ | ||
if(typeof events!=='object'){ | ||
throw TypeError('events must be an object'); | ||
} | ||
var reducers= options.reducers; | ||
var index= findTargetIndex.call(emitter, target); | ||
var observer; | ||
if(index===-1){ | ||
observer= new TargetObserver(emitter, target, options); | ||
}else{ | ||
observer= emitter._observers[index]; | ||
} | ||
var keys= ownKeys(events); | ||
var len= keys.length; | ||
var event; | ||
var isSingleReducer= typeof reducers==='function'; | ||
for(var i=0; i<len; i++){ | ||
event= keys[i]; | ||
observer.subscribe( | ||
event, | ||
events[event] || event, | ||
isSingleReducer ? reducers : reducers && reducers[event] | ||
); | ||
} | ||
} | ||
isArray(events)? | ||
listen(toObject(events)) : | ||
(typeof events==='string'? listen(toObject(events.split(/\s+/))): listen(events)); | ||
return this; | ||
}; | ||
EventEmitter.prototype.stopListeningTo = function (target, event) { | ||
var observers = this._observers; | ||
if(!observers){ | ||
return false; | ||
} | ||
var i = observers.length; | ||
var observer; | ||
var matched= false; | ||
if(target && typeof target!=='object'){ | ||
throw TypeError('target should be an object'); | ||
} | ||
while (i-- > 0) { | ||
observer = observers[i]; | ||
if (!target || observer._target === target) { | ||
observer.unsubscribe(event); | ||
matched= true; | ||
} | ||
} | ||
return matched; | ||
}; | ||
// By default EventEmitters will print a warning if more than | ||
@@ -426,24 +809,23 @@ // 10 listeners are added to it. This is a useful default which | ||
EventEmitter.prototype.once = function(event, fn) { | ||
return this._once(event, fn, false); | ||
EventEmitter.prototype.once = function(event, fn, options) { | ||
return this._once(event, fn, false, options); | ||
}; | ||
EventEmitter.prototype.prependOnceListener = function(event, fn) { | ||
return this._once(event, fn, true); | ||
EventEmitter.prototype.prependOnceListener = function(event, fn, options) { | ||
return this._once(event, fn, true, options); | ||
}; | ||
EventEmitter.prototype._once = function(event, fn, prepend) { | ||
this._many(event, 1, fn, prepend); | ||
return this; | ||
EventEmitter.prototype._once = function(event, fn, prepend, options) { | ||
return this._many(event, 1, fn, prepend, options); | ||
}; | ||
EventEmitter.prototype.many = function(event, ttl, fn) { | ||
return this._many(event, ttl, fn, false); | ||
EventEmitter.prototype.many = function(event, ttl, fn, options) { | ||
return this._many(event, ttl, fn, false, options); | ||
}; | ||
EventEmitter.prototype.prependMany = function(event, ttl, fn) { | ||
return this._many(event, ttl, fn, true); | ||
EventEmitter.prototype.prependMany = function(event, ttl, fn, options) { | ||
return this._many(event, ttl, fn, true, options); | ||
}; | ||
EventEmitter.prototype._many = function(event, ttl, fn, prepend) { | ||
EventEmitter.prototype._many = function(event, ttl, fn, prepend, options) { | ||
var self = this; | ||
@@ -464,5 +846,3 @@ | ||
this._on(event, listener, prepend); | ||
return self; | ||
return this._on(event, listener, prepend, options); | ||
}; | ||
@@ -477,3 +857,4 @@ | ||
var type = arguments[0]; | ||
var type = arguments[0], ns, wildcard= this.wildcard, kind; | ||
var args,l,i,j, containsSymbol; | ||
@@ -486,4 +867,28 @@ if (type === 'newListener' && !this._newListener) { | ||
if (wildcard) { | ||
kind = typeof type; | ||
if (kind === 'string') { | ||
ns = type.split(this.delimiter); | ||
} else { | ||
if(kind==='symbol'){ | ||
ns= [type]; | ||
}else{ | ||
ns = type.slice(); | ||
l= type.length; | ||
if(symbolsSupported) { | ||
for (i = 0; i < l; i++) { | ||
if (typeof type[i] === 'symbol') { | ||
containsSymbol = true; | ||
break; | ||
} | ||
} | ||
} | ||
if(!containsSymbol){ | ||
type = type.join(this.delimiter); | ||
} | ||
} | ||
} | ||
} | ||
var al = arguments.length; | ||
var args,l,i,j; | ||
var handler; | ||
@@ -493,6 +898,2 @@ | ||
handler = this._all.slice(); | ||
if (al > 3) { | ||
args = new Array(al); | ||
for (j = 0; j < al; j++) args[j] = arguments[j]; | ||
} | ||
@@ -512,3 +913,3 @@ for (i = 0, l = handler.length; i < l; i++) { | ||
default: | ||
handler[i].apply(this, args); | ||
handler[i].apply(this, arguments); | ||
} | ||
@@ -518,5 +919,4 @@ } | ||
if (this.wildcard) { | ||
if (wildcard) { | ||
handler = []; | ||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | ||
searchListenerTree.call(this, handler, ns, this.listenerTree, 0); | ||
@@ -590,3 +990,4 @@ } else { | ||
var type = arguments[0]; | ||
var type = arguments[0], wildcard= this.wildcard, ns, kind, containsSymbol; | ||
var args,l,i,j; | ||
@@ -597,13 +998,33 @@ if (type === 'newListener' && !this._newListener) { | ||
if (wildcard) { | ||
kind = typeof type; | ||
if (kind === 'string') { | ||
ns = type.split(this.delimiter); | ||
} else { | ||
if(kind==='symbol'){ | ||
ns= [type]; | ||
}else{ | ||
ns = type.slice(); | ||
l= type.length; | ||
if(symbolsSupported) { | ||
for (i = 0; i < l; i++) { | ||
if (typeof type[i] === 'symbol') { | ||
containsSymbol = true; | ||
break; | ||
} | ||
} | ||
} | ||
if(!containsSymbol){ | ||
type = type.join(this.delimiter); | ||
} | ||
} | ||
} | ||
} | ||
var promises= []; | ||
var al = arguments.length; | ||
var args,l,i,j; | ||
var handler; | ||
if (this._all) { | ||
if (al > 3) { | ||
args = new Array(al); | ||
for (j = 1; j < al; j++) args[j] = arguments[j]; | ||
} | ||
for (i = 0, l = this._all.length; i < l; i++) { | ||
@@ -622,3 +1043,3 @@ this.event = type; | ||
default: | ||
promises.push(this._all[i].apply(this, args)); | ||
promises.push(this._all[i].apply(this, arguments)); | ||
} | ||
@@ -628,5 +1049,4 @@ } | ||
if (this.wildcard) { | ||
if (wildcard) { | ||
handler = []; | ||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | ||
searchListenerTree.call(this, handler, ns, this.listenerTree, 0); | ||
@@ -687,8 +1107,8 @@ } else { | ||
EventEmitter.prototype.on = function(type, listener) { | ||
return this._on(type, listener, false); | ||
EventEmitter.prototype.on = function(type, listener, options) { | ||
return this._on(type, listener, false, options); | ||
}; | ||
EventEmitter.prototype.prependListener = function(type, listener) { | ||
return this._on(type, listener, true); | ||
EventEmitter.prototype.prependListener = function(type, listener, options) { | ||
return this._on(type, listener, true, options); | ||
}; | ||
@@ -725,3 +1145,3 @@ | ||
EventEmitter.prototype._on = function(type, listener, prepend) { | ||
EventEmitter.prototype._on = function(type, listener, prepend, options) { | ||
if (typeof type === 'function') { | ||
@@ -737,6 +1157,15 @@ this._onAny(type, listener); | ||
var returnValue= this, temp; | ||
if (options !== undefined) { | ||
temp = setupListener.call(this, type, listener, options); | ||
listener = temp[0]; | ||
returnValue = temp[1]; | ||
} | ||
// To avoid recursion in the case that type == "newListeners"! Before | ||
// adding it to the listeners, first emit "newListeners". | ||
if (this._newListener) | ||
this.emit('newListener', type, listener); | ||
if (this._newListener) { | ||
this.emit('newListener', type, listener); | ||
} | ||
@@ -751,4 +1180,3 @@ if (this.wildcard) { | ||
this._events[type] = listener; | ||
} | ||
else { | ||
} else { | ||
if (typeof this._events[type] === 'function') { | ||
@@ -777,3 +1205,3 @@ // Change to array. | ||
return this; | ||
return returnValue; | ||
}; | ||
@@ -853,21 +1281,3 @@ | ||
function recursivelyGarbageCollect(root) { | ||
if (root === undefined) { | ||
return; | ||
} | ||
var keys = Object.keys(root); | ||
for (var i in keys) { | ||
var key = keys[i]; | ||
var obj = root[key]; | ||
if ((obj instanceof Function) || (typeof obj !== "object") || (obj === null)) | ||
continue; | ||
if (Object.keys(obj).length > 0) { | ||
recursivelyGarbageCollect(root[key]); | ||
} | ||
if (Object.keys(obj).length === 0) { | ||
delete root[key]; | ||
} | ||
} | ||
} | ||
recursivelyGarbageCollect(this.listenerTree); | ||
this.listenerTree && recursivelyGarbageCollect(this.listenerTree); | ||
@@ -902,3 +1312,3 @@ return this; | ||
EventEmitter.prototype.removeAllListeners = function(type) { | ||
EventEmitter.prototype.removeAllListeners = function (type) { | ||
if (type === undefined) { | ||
@@ -913,8 +1323,8 @@ !this._events || init.call(this); | ||
for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) { | ||
for (var iLeaf = 0; iLeaf < leafs.length; iLeaf++) { | ||
var leaf = leafs[iLeaf]; | ||
leaf._listeners = null; | ||
} | ||
} | ||
else if (this._events) { | ||
this.listenerTree && recursivelyGarbageCollect(this.listenerTree); | ||
} else if (this._events) { | ||
this._events[type] = null; | ||
@@ -925,21 +1335,55 @@ } | ||
EventEmitter.prototype.listeners = function(type) { | ||
if (this.wildcard) { | ||
var handlers = []; | ||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | ||
searchListenerTree.call(this, handlers, ns, this.listenerTree, 0); | ||
return handlers; | ||
} | ||
EventEmitter.prototype.listeners = function (type) { | ||
var _events = this._events; | ||
var keys, listeners, allListeners; | ||
var i; | ||
var listenerTree; | ||
this._events || init.call(this); | ||
if (type === undefined) { | ||
if (this.wildcard) { | ||
throw Error('event name required for wildcard emitter'); | ||
} | ||
if (!this._events[type]) this._events[type] = []; | ||
if (!isArray(this._events[type])) { | ||
this._events[type] = [this._events[type]]; | ||
if (!_events) { | ||
return []; | ||
} | ||
keys = ownKeys(_events); | ||
i = keys.length; | ||
allListeners = []; | ||
while (i-- > 0) { | ||
listeners = _events[keys[i]]; | ||
if (typeof listeners === 'function') { | ||
allListeners.push(listeners); | ||
} else { | ||
allListeners.push.apply(allListeners, listeners); | ||
} | ||
} | ||
return allListeners; | ||
} else { | ||
if (this.wildcard) { | ||
listenerTree= this.listenerTree; | ||
if(!listenerTree) return []; | ||
var handlers = []; | ||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | ||
searchListenerTree.call(this, handlers, ns, listenerTree, 0); | ||
return handlers; | ||
} | ||
if (!_events) { | ||
return []; | ||
} | ||
listeners = _events[type]; | ||
if (!listeners) { | ||
return []; | ||
} | ||
return typeof listeners === 'function' ? [listeners] : listeners; | ||
} | ||
return this._events[type]; | ||
}; | ||
EventEmitter.prototype.eventNames = function(){ | ||
return Object.keys(this._events); | ||
EventEmitter.prototype.eventNames = function(nsAsArray){ | ||
var _events= this._events; | ||
return this.wildcard? collectTreeEvents.call(this, this.listenerTree, [], null, nsAsArray) : (_events? ownKeys(_events) : []); | ||
}; | ||
@@ -951,2 +1395,16 @@ | ||
EventEmitter.prototype.hasListeners = function (type) { | ||
if (this.wildcard) { | ||
var handlers = []; | ||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | ||
searchListenerTree.call(this, handlers, ns, this.listenerTree, 0); | ||
return handlers.length > 0; | ||
} | ||
var _events = this._events; | ||
var _all = this._all; | ||
return !!(_all && _all.length || _events && (type === undefined ? ownKeys(_events).length : _events[type])); | ||
}; | ||
EventEmitter.prototype.listenersAny = function() { | ||
@@ -1070,3 +1528,3 @@ | ||
defaultMaxListeners: { | ||
get: function(){ | ||
get: function () { | ||
return prototype._maxListeners; | ||
@@ -1094,3 +1552,4 @@ }, | ||
configurable: true | ||
} | ||
}, | ||
_observers: {value: null, writable: true, configurable: true} | ||
}); | ||
@@ -1097,0 +1556,0 @@ |
{ | ||
"name": "eventemitter2", | ||
"version": "6.3.1", | ||
"description": "A Node.js event emitter implementation with namespaces, wildcards, TTL and browser support.", | ||
"version": "6.4.0", | ||
"description": "A feature-rich Node.js event emitter implementation with namespaces, wildcards, TTL, async listeners and browser/worker support.", | ||
"keywords": [ | ||
@@ -9,3 +9,12 @@ "event", | ||
"emitter", | ||
"eventemitter" | ||
"eventemitter", | ||
"addEventListener", | ||
"addListener", | ||
"pub/sub", | ||
"emit", | ||
"emits", | ||
"on", | ||
"once", | ||
"publish", | ||
"subscribe" | ||
], | ||
@@ -23,12 +32,19 @@ "author": "hij1nx <paolo@async.ly> http://twitter.com/hij1nx", | ||
"devDependencies": { | ||
"benchmark": ">= 0.2.2", | ||
"benchmark": "^2.1.4", | ||
"bluebird": "^3.7.2", | ||
"coveralls": "^3.0.11", | ||
"mocha": "^7.1.1", | ||
"nodeunit": "*", | ||
"nyc": "^11.4.1" | ||
"nyc": "^15.0.0" | ||
}, | ||
"main": "./lib/eventemitter2.js", | ||
"scripts": { | ||
"test": "nodeunit test/simple/ test/wildcardEvents/", | ||
"coverage": "nyc --check-coverage npm run test", | ||
"benchmark": "node test/perf/benchmark.js" | ||
"test": "mocha ./test/loader.js --exit --timeout=3000", | ||
"test:legacy": "nodeunit test/simple/ test/wildcardEvents/", | ||
"test:coverage": "nyc --check-coverage npm run test", | ||
"coverage:report": "nyc report --reporter=html --reporter=text", | ||
"coveralls": "nyc report --reporter=text-lcov | coveralls", | ||
"benchmark": "node test/perf/benchmark.js", | ||
"prepublishOnly": "npm run test:coverage", | ||
"postversion": "git push && git push --tags" | ||
}, | ||
@@ -45,6 +61,6 @@ "files": [ | ||
"nyc": { | ||
"lines": 83, | ||
"functions": 84, | ||
"branches": 79, | ||
"statements": 83, | ||
"lines": 80, | ||
"functions": 80, | ||
"branches": 75, | ||
"statements": 80, | ||
"watermarks": { | ||
@@ -68,2 +84,5 @@ "lines": [ | ||
}, | ||
"include": [ | ||
"lib/**/*.js" | ||
], | ||
"reporter": [ | ||
@@ -70,0 +89,0 @@ "lcov", |
414
README.md
@@ -1,2 +0,3 @@ | ||
[![Codeship](https://img.shields.io/codeship/3ad58940-4c7d-0131-15d5-5a8cd3f550f8.svg?maxAge=2592000)]() | ||
[![Build Status](https://travis-ci.com/EventEmitter2/EventEmitter2.svg?branch=master)](https://travis-ci.com/EventEmitter2/EventEmitter2) | ||
[![Coverage Status](https://coveralls.io/repos/github/EventEmitter2/EventEmitter2/badge.svg?branch=master)](https://coveralls.io/github/EventEmitter2/EventEmitter2?branch=master) | ||
[![NPM version](https://badge.fury.io/js/eventemitter2.svg)](http://badge.fury.io/js/eventemitter2) | ||
@@ -8,12 +9,23 @@ [![Dependency Status](https://img.shields.io/david/asyncly/eventemitter2.svg)](https://david-dm.org/asyncly/eventemitter2) | ||
EventEmitter2 is an implementation of the EventEmitter module found in Node.js. In addition to having a better benchmark performance than EventEmitter and being browser-compatible, it also extends the interface of EventEmitter with additional non-breaking features. | ||
EventEmitter2 is an implementation of the EventEmitter module found in Node.js. | ||
In addition to having a better benchmark performance than EventEmitter and being browser-compatible, | ||
it also extends the interface of EventEmitter with many additional non-breaking features. | ||
If you like this project please show your support with a [GitHub :star:](https://github.com/EventEmitter2/EventEmitter2/stargazers)! | ||
# DESCRIPTION | ||
### FEATURES | ||
- ES5 compatible UMD module, that supports node.js, browser and workers of any kind | ||
- Namespaces/Wildcards | ||
- Times To Listen (TTL), extends the `once` concept with [`many`](#emittermanyevent-timestolisten-listener) | ||
- The [emitAsync](#emitteremitasyncevent-arg1-arg2-) method to return the results of the listeners via Promise.all | ||
- Feature-rich [waitFor](#emitterwaitforevent-options) method to wait for events using promises | ||
- Extended version of the [events.once](#eventemitter2onceemitter-name-options) method from the [node events API](https://nodejs.org/api/events.html#events_events_once_emitter_name) | ||
- [Any](#emitteronanylistener) listeners | ||
- Times To Listen (TTL), extends the `once` concept with [`many`](#emittermanyevent--eventns-timestolisten-listener-options) | ||
- [Async listeners](#emitteronevent-listener-options-objectboolean) (using setImmediate|setTimeout|nextTick) with promise|async function support | ||
- The [emitAsync](#emitteremitasyncevent--eventns-arg1-arg2-) method to return the results of the listeners via Promise.all | ||
- Subscription methods ([on](#emitteronevent-listener-options-objectboolean), [once](#emitterprependoncelistenerevent--eventns-listener-options), [many](#emittermanyevent--eventns-timestolisten-listener-options), ...) can return a | ||
[listener](#listener) object that makes it easy to remove the subscription when needed - just call the listener.off() method. | ||
- Feature-rich [waitFor](#emitterwaitforevent--eventns-options) method to wait for events using promises | ||
- [listenTo](#listentotargetemitter-events-objectevent--eventns-function-options) & [stopListeningTo](#stoplisteningtotarget-object-event-event--eventns-boolean) methods | ||
for listening to an external event emitter of any kind and propagate its events through itself using optional reducers/filters | ||
- Extended version of the [events.once](#eventemitter2onceemitter-event--eventns-options) method from the [node events API](https://nodejs.org/api/events.html#events_events_once_emitter_name) | ||
- Browser & Workers environment compatibility | ||
@@ -23,6 +35,12 @@ - Demonstrates good performance in benchmarks | ||
``` | ||
EventEmitterHeatUp x 3,728,965 ops/sec \302\2610.68% (60 runs sampled) | ||
EventEmitter x 2,822,904 ops/sec \302\2610.74% (63 runs sampled) | ||
EventEmitter2 x 7,251,227 ops/sec \302\2610.55% (58 runs sampled) | ||
EventEmitter2 (wild) x 3,220,268 ops/sec \302\2610.44% (65 runs sampled) | ||
Platform: win32, x64, 15267MB | ||
Node version: v13.11.0 | ||
CPU: 4 x AMD Ryzen 3 2200U with Radeon Vega Mobile Gfx @ 2495MHz | ||
---------------------------------------------------------------- | ||
EventEmitterHeatUp x 3,167,076 ops/sec ±3.17% (59 runs sampled) | ||
EventEmitter x 3,190,460 ops/sec ±3.20% (66 runs sampled) | ||
EventEmitter2 x 11,278,456 ops/sec ±4.26% (60 runs sampled) | ||
EventEmitter2 (wild) x 4,620,369 ops/sec ±4.46% (61 runs sampled) | ||
EventEmitter3 x 10,309,717 ops/sec ±3.89% (64 runs sampled) | ||
Fastest is EventEmitter2 | ||
@@ -33,41 +51,26 @@ ``` | ||
- The EventEmitter2 constructor takes an optional configuration object. | ||
- The EventEmitter2 constructor takes an optional configuration object with the following default values: | ||
```javascript | ||
var EventEmitter2 = require('eventemitter2').EventEmitter2; | ||
var server = new EventEmitter2({ | ||
var EventEmitter2 = require('eventemitter2'); | ||
var emitter = new EventEmitter2({ | ||
// | ||
// set this to `true` to use wildcards. It defaults to `false`. | ||
// | ||
wildcard: true, | ||
// set this to `true` to use wildcards | ||
wildcard: false, | ||
// | ||
// the delimiter used to segment namespaces, defaults to `.`. | ||
// | ||
delimiter: '::', | ||
// | ||
// set this to `true` if you want to emit the newListener event. The default value is `false`. | ||
// | ||
// the delimiter used to segment namespaces | ||
delimiter: '.', | ||
// set this to `true` if you want to emit the newListener event | ||
newListener: false, | ||
// | ||
// set this to `true` if you want to emit the removeListener event. The default value is `false`. | ||
// | ||
// set this to `true` if you want to emit the removeListener event | ||
removeListener: false, | ||
// | ||
// the maximum amount of listeners that can be assigned to an event, default 10. | ||
// | ||
maxListeners: 20, | ||
// | ||
// show event name in memory leak message when more than maximum amount of listeners is assigned, default false | ||
// | ||
// the maximum amount of listeners that can be assigned to an event | ||
maxListeners: 10, | ||
// show event name in memory leak message when more than maximum amount of listeners is assigned | ||
verboseMemoryLeak: false, | ||
// | ||
// disable throwing uncaughtException if an error event is emitted and it has no listeners | ||
// | ||
ignoreErrors: false | ||
@@ -80,6 +83,15 @@ }); | ||
```javascript | ||
server.on('foo.*', function(value1, value2) { | ||
emitter.on('foo.*', function(value1, value2) { | ||
console.log(this.event, value1, value2); | ||
}); | ||
emitter.emit('foo.bar', 1, 2); // 'foo.bar' 1 2 | ||
emitter.emit(['foo', 'bar'], 3, 4); // 'foo.bar' 3 4 | ||
emitter.emit(Symbol(), 5, 6); // Symbol() 5 6 | ||
emitter.emit(['foo', Symbol(), 7, 8]); // ['foo', Symbol()] 7 8 | ||
``` | ||
**Note**: Generally this.event is normalized to a string ('event', 'event.test'), | ||
except the cases when event is a symbol or namespace contains a symbol. | ||
In these cases this.event remains as is (symbol and array). | ||
@@ -105,7 +117,81 @@ - Fire an event N times and then remove it, an extension of the `once` concept. | ||
```console | ||
$ npm install --save eventemitter2 | ||
$ npm install eventemitter2 | ||
``` | ||
Or you can use unpkg.com CDN to import this [module](https://unpkg.com/eventemitter2) as a script directly from the browser | ||
# API | ||
### Types definition | ||
- `Event`: string | symbol | ||
- `EventNS`: string | Event [] | ||
## Class EventEmitter2 | ||
### instance: | ||
- [emit(event: event | eventNS, ...values: any[]): boolean](#emitteremitevent--eventns-arg1-arg2-); | ||
- [emitAsync(event: event | eventNS, ...values: any[]): Promise<any[]>](#emitteremitasyncevent--eventns-arg1-arg2-) | ||
- [addListener(event: event | eventNS, listener: ListenerFn, boolean|options?: object): this|Listener](#emitteraddlistenerevent-listener-options-objectboolean) | ||
- [on(event: event | eventNS, listener: ListenerFn, boolean|options?: object): this|Listener](#emitteraddlistenerevent-listener-options-objectboolean) | ||
- [once(event: event | eventNS, listener: ListenerFn, boolean|options?: object): this|Listener](#emitteronceevent--eventns-listener-options) | ||
- [many(event: event | eventNS, timesToListen: number, listener: ListenerFn, boolean|options?: object): this|Listener](#emittermanyevent--eventns-timestolisten-listener-options) | ||
- [prependMany(event: event | eventNS, timesToListen: number, listener: ListenerFn, boolean|options?: object): this|Listener](#emitterprependanylistener) | ||
- [prependOnceListener(event: event | eventNS, listener: ListenerFn, boolean|options?: object): this|Listener](#emitterprependoncelistenerevent--eventns-listener-options) | ||
- [prependListener(event: event | eventNS, listener: ListenerFn, boolean|options?: object): this|Listener](#emitterprependlistenerevent-listener-options) | ||
- [prependAny(listener: EventAndListener): this](#emitterprependanylistener) | ||
- [onAny(listener: EventAndListener): this](#emitteronanylistener) | ||
- [offAny(listener: ListenerFn): this](#emitteroffanylistener) | ||
- [removeListener(event: event | eventNS, listener: ListenerFn): this](#emitterremovelistenerevent--eventns-listener) | ||
- [off(event: event | eventNS, listener: ListenerFn): this](#emitteroffevent--eventns-listener) | ||
- [removeAllListeners(event?: event | eventNS): this](#emitterremovealllistenersevent--eventns) | ||
- [setMaxListeners(n: number): void](#emittersetmaxlistenersn) | ||
- [getMaxListeners(): number](#emittergetmaxlisteners) | ||
- [eventNames(nsAsArray?: boolean): string[]](#emittereventnamesnsasarray) | ||
- [listeners(event: event | eventNS): ListenerFn[]](#emitterlistenersevent--eventns) | ||
- [listenersAny(): ListenerFn[]](#emitterlistenersany) | ||
- [hasListeners(event?: event | eventNS): Boolean](#haslistenersevent--eventnsstringboolean) | ||
- [waitFor(event: event | eventNS, timeout?: number): CancelablePromise<any[]>](#emitterwaitforevent--eventns-timeout) | ||
- [waitFor(event: event | eventNS, filter?: WaitForFilter): CancelablePromise<any[]>](#emitterwaitforevent--eventns-filter) | ||
- [waitFor(event: event | eventNS, options?: WaitForOptions): CancelablePromise<any[]>](#emitterwaitforevent--eventns-options) | ||
- [listenTo(target: GeneralEventEmitter, event: event | eventNS, options?: ListenToOptions): this](#listentotargetemitter-events-objectevent--eventns-function-options) | ||
- [listenTo(target: GeneralEventEmitter, events: (event | eventNS)[], options?: ListenToOptions): this](#listentotargetemitter-events-event--eventns-options) | ||
- [listenTo(target: GeneralEventEmitter, events: Object<event | eventNS, Function>, options?: ListenToOptions): this](#listentotargetemitter-events-objectevent--eventns-function-options) | ||
- [stopListeningTo(target?: GeneralEventEmitter, event?: event | eventNS): Boolean](#stoplisteningtarget-object-event-event--eventns-boolean) | ||
### static: | ||
- [static once(emitter: EventEmitter2, event: string | symbol, options?: OnceOptions): CancelablePromise<any[]>](#eventemitter2onceemitter-event--eventns-options) | ||
- [static defaultMaxListeners: number](#eventemitter2defaultmaxlisteners) | ||
The `event` argument specified in the API declaration can be a string or symbol for a simple event emitter | ||
and a string|symbol|Array(string|symbol) in a case of a wildcard emitter; | ||
When an `EventEmitter` instance experiences an error, the typical action is | ||
@@ -136,4 +222,7 @@ to emit an `error` event. Error events are treated as a special case. | ||
```javascript | ||
emitter.emit(Symbol()); | ||
emitter.emit('foo'); | ||
emitter.emit('foo.bazz'); | ||
emitter.emit(['foo', 'bar']); | ||
emitter.emit(['foo', Symbol()]); | ||
``` | ||
@@ -152,2 +241,3 @@ | ||
emitter.emit('foo.bar.baz'); | ||
emitter.emit(['foo', Symbol(), 'baz'); | ||
```` | ||
@@ -158,4 +248,4 @@ | ||
### emitter.addListener(event, listener) | ||
### emitter.on(event, listener) | ||
### emitter.addListener(event, listener, options?: object|boolean) | ||
### emitter.on(event, listener, options?: object|boolean) | ||
@@ -169,3 +259,2 @@ Adds a listener to the end of the listeners array for the specified event. | ||
``` | ||
```javascript | ||
@@ -177,4 +266,91 @@ server.on('data', function(value) { | ||
### emitter.prependListener(event, listener) | ||
**Options:** | ||
- `async:boolean= false`- invoke the listener in async mode using setImmediate (fallback to setTimeout if not available) | ||
or process.nextTick depending on the `nextTick` option. | ||
- `nextTick:boolean= false`- use process.nextTick instead of setImmediate to invoke the listener asynchronously. | ||
- `promisify:boolean= false`- additionally wraps the listener to a Promise for later invocation using `emitAsync` method. | ||
This option will be activated by default if its value is `undefined` | ||
and the listener function is an `asynchronous function` (whose constructor name is `AsyncFunction`). | ||
- `objectify:boolean= false`- activates returning a [listener](#listener) object instead of 'this' by the subscription method. | ||
#### listener | ||
The listener object has the following properties: | ||
- `emitter: EventEmitter2` - reference to the event emitter instance | ||
- `event: event|eventNS` - subscription event | ||
- `listener: Function` - reference to the listener | ||
- `off(): Function`- removes the listener (voids the subscription) | ||
````javascript | ||
var listener= emitter.on('event', function(){ | ||
console.log('hello!'); | ||
}, {objectify: true}); | ||
emitter.emit('event'); | ||
listener.off(); | ||
```` | ||
**Note:** If the options argument is `true` it will be considered as `{promisify: true}` | ||
**Note:** If the options argument is `false` it will be considered as `{async: true}` | ||
```javascript | ||
var EventEmitter2= require('eventemitter2'); | ||
var emitter= new EventEmitter2(); | ||
emitter.on('event', function(){ | ||
console.log('The event was raised!'); | ||
}, {async: true}); | ||
emitter.emit('event'); | ||
console.log('emitted'); | ||
``` | ||
Since the `async` option was set the output from the code above is as follows: | ||
```` | ||
emitted | ||
The event was raised! | ||
```` | ||
If the listener is an async function or function which returns a promise, use the `promisify` option as follows: | ||
```javascript | ||
var EventEmitter2= require('eventemitter2'); | ||
var emitter= new EventEmitter2(); | ||
emitter.on('event', function(){ | ||
console.log('The event was raised!'); | ||
return new Promise(function(resolve){ | ||
console.log('listener resolved'); | ||
setTimeout(resolve, 1000); | ||
}); | ||
}, {promisify: true}); | ||
emitter.emitAsync('event').then(function(){ | ||
console.log('all listeners were resolved!'); | ||
}); | ||
console.log('emitted'); | ||
```` | ||
Output: | ||
```` | ||
emitted | ||
The event was raised! | ||
listener resolved | ||
all listeners were resolved! | ||
```` | ||
If the `promisify` option is false (default value) the output of the same code is as follows: | ||
```` | ||
The event was raised! | ||
listener resolved | ||
emitted | ||
all listeners were resolved! | ||
```` | ||
### emitter.prependListener(event, listener, options?) | ||
Adds a listener to the beginning of the listeners array for the specified event. | ||
@@ -188,3 +364,6 @@ | ||
**options:** | ||
`options?`: See the [addListener options](#emitteronevent-listener-options-objectboolean) | ||
### emitter.onAny(listener) | ||
@@ -220,3 +399,3 @@ | ||
#### emitter.once(event, listener) | ||
#### emitter.once(event | eventNS, listener, options?) | ||
@@ -232,4 +411,8 @@ Adds a **one time** listener for the event. The listener is invoked | ||
#### emitter.prependOnceListener(event, listener) | ||
**options:** | ||
`options?`: See the [addListener options](#emitteronevent-listener-options-objectboolean) | ||
#### emitter.prependOnceListener(event | eventNS, listener, options?) | ||
Adds a **one time** listener for the event. The listener is invoked | ||
@@ -245,4 +428,8 @@ only the first time the event is fired, after which it is removed. | ||
### emitter.many(event, timesToListen, listener) | ||
**options:** | ||
`options?`: See the [addListener options](#emitteronevent-listener-options-objectboolean) | ||
### emitter.many(event | eventNS, timesToListen, listener, options?) | ||
Adds a listener that will execute **n times** for the event before being | ||
@@ -258,4 +445,8 @@ removed. The listener is invoked only the first **n times** the event is | ||
### emitter.prependMany(event, timesToListen, listener) | ||
**options:** | ||
`options?`: See the [addListener options](#emitteronevent-listener-options-objectboolean) | ||
### emitter.prependMany(event | eventNS, timesToListen, listener, options?) | ||
Adds a listener that will execute **n times** for the event before being | ||
@@ -272,6 +463,8 @@ removed. The listener is invoked only the first **n times** the event is | ||
**options:** | ||
`options?`: See the [addListener options](#emitteronevent-listener-options-objectboolean) | ||
### emitter.removeListener(event, listener) | ||
### emitter.off(event, listener) | ||
### emitter.removeListener(event | eventNS, listener) | ||
### emitter.off(event | eventNS, listener) | ||
@@ -291,3 +484,3 @@ Remove a listener from the listener array for the specified event. | ||
### emitter.removeAllListeners([event]) | ||
### emitter.removeAllListeners([event | eventNS]) | ||
@@ -310,3 +503,3 @@ Removes all listeners, or those of the specified event. | ||
### emitter.listeners(event) | ||
### emitter.listeners(event | eventNS) | ||
@@ -335,8 +528,7 @@ Returns an array of listeners for the specified event. This array can be | ||
### emitter.emit(event, [arg1], [arg2], [...]) | ||
### emitter.emit(event | eventNS, [arg1], [arg2], [...]) | ||
Execute each of the listeners that may be listening for the specified event | ||
name in order with the list of arguments. | ||
### emitter.emitAsync(event, [arg1], [arg2], [...]) | ||
### emitter.emitAsync(event | eventNS, [arg1], [arg2], [...]) | ||
@@ -375,5 +567,5 @@ Return the results of the listeners via [Promise.all](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). | ||
### emitter.waitFor(event, [options]) | ||
### emitter.waitFor(event, [timeout]) | ||
### emitter.waitFor(event, [filter]) | ||
### emitter.waitFor(event | eventNS, [options]) | ||
### emitter.waitFor(event | eventNS, [timeout]) | ||
### emitter.waitFor(event | eventNS, [filter]) | ||
@@ -428,7 +620,7 @@ Returns a thenable object (promise interface) that resolves when a specific event occurs | ||
```` | ||
### emitter.eventNames() | ||
### emitter.eventNames(nsAsArray) | ||
Returns an array listing the events for which the emitter has registered listeners. The values in the array will be strings. | ||
```javascript | ||
var emitter= new EventEmitter2(); | ||
emitter.on('foo', () => {}); | ||
@@ -440,4 +632,95 @@ emitter.on('bar', () => {}); | ||
``` | ||
### listenTo(targetEmitter, events: event | eventNS, options?) | ||
### EventEmitter2.once(emitter, name, [options]) | ||
### listenTo(targetEmitter, events: (event | eventNS)[], options?) | ||
### listenTo(targetEmitter, events: Object<event | eventNS, Function>, options?) | ||
Listens to the events emitted by an external emitter and propagate them through itself. | ||
The target object could be of any type that implements methods for subscribing and unsubscribing to its events. | ||
By default this method attempts to use `addListener`/`removeListener`, `on`/`off` and `addEventListener`/`removeEventListener` pairs, | ||
but you able to define own hooks `on(event, handler)` and `off(event, handler)` in the options object to use | ||
custom subscription API. In these hooks `this` refers to the target object. | ||
The options object has the following interface: | ||
- `on(event, handler): void` | ||
- `off(event, handler): void` | ||
- `reducer: (Function) | (Object<Function>): Boolean` | ||
In case you selected the `newListener` and `removeListener` options when creating the emitter, | ||
the subscription to the events of the target object will be conditional, | ||
depending on whether there are listeners in the emitter that could listen them. | ||
````javascript | ||
var EventEmitter2 = require('EventEmitter2'); | ||
var http = require('http'); | ||
var server = http.createServer(function(request, response){ | ||
console.log(request.url); | ||
response.end('Hello Node.js Server!') | ||
}).listen(3000); | ||
server.on('connection', function(req, socket, head){ | ||
console.log('connect'); | ||
}); | ||
// activate the ability to attach listeners on demand | ||
var emitter= new EventEmitter2({ | ||
newListener: true, | ||
removeListener: true | ||
}); | ||
emitter.listenTo(server, { | ||
'connection': 'localConnection', | ||
'close': 'close' | ||
}, { | ||
reducers: { | ||
connection: function(event){ | ||
console.log('event name:' + event.name); //'localConnection' | ||
console.log('original event name:' + event.original); //'connection' | ||
return event.data[0].remoteAddress==='::1'; | ||
} | ||
} | ||
}); | ||
emitter.on('localConnection', function(socket){ | ||
console.log('local connection', socket.remoteAddress); | ||
}); | ||
setTimeout(function(){ | ||
emitter.stopListeningTo(server); | ||
}, 30000); | ||
```` | ||
### stopListeningTo(target?: Object, event: event | eventNS): Boolean | ||
Stops listening the targets. Returns true if some listener was removed. | ||
### hasListeners(event | eventNS?:String):Boolean | ||
Checks whether emitter has any listeners. | ||
### emitter.listeners(event | eventNS) | ||
Returns the array of listeners for the event named eventName. | ||
In wildcard mode this method returns namespaces as strings: | ||
````javascript | ||
var emitter= new EventEmitter2({ | ||
wildcard: true | ||
}); | ||
emitter.on('a.b.c', function(){}); | ||
emitter.on(['z', 'x', 'c'], function(){}); | ||
console.log(emitter.eventNames()) // [ 'z.x.c', 'a.b.c' ] | ||
```` | ||
If some namespace contains a Symbol member or the `nsAsArray` option is set the method will return namespace as an array of its members; | ||
````javascript | ||
var emitter= new EventEmitter2({ | ||
wildcard: true | ||
}); | ||
emitter.on('a.b.c', function(){}); | ||
emitter.on(['z', 'x', Symbol()], function(){}); | ||
console.log(emitter.eventNames()) // [ [ 'z', 'x', Symbol() ], 'a.b.c' ] | ||
```` | ||
### EventEmitter2.once(emitter, event | eventNS, [options]) | ||
Creates a cancellable Promise that is fulfilled when the EventEmitter emits the given event or that is rejected | ||
@@ -516,9 +799,4 @@ when the EventEmitter emits 'error'. | ||
### emitter.listeners(eventName) | ||
Returns the array of listeners for the event named eventName. | ||
### EventEmitter2.defaultMaxListeners | ||
Sets default max listeners count globally for all instances, including those created before the change is made. |
80909
1457
780
6