-
Star
(207)
You must be signed in to star a gist -
Fork
(37)
You must be signed in to fork a gist
-
-
Save mudge/5830382 to your computer and use it in GitHub Desktop.
| /* Polyfill indexOf. */ | |
| var indexOf; | |
| if (typeof Array.prototype.indexOf === 'function') { | |
| indexOf = function (haystack, needle) { | |
| return haystack.indexOf(needle); | |
| }; | |
| } else { | |
| indexOf = function (haystack, needle) { | |
| var i = 0, length = haystack.length, idx = -1, found = false; | |
| while (i < length && !found) { | |
| if (haystack[i] === needle) { | |
| idx = i; | |
| found = true; | |
| } | |
| i++; | |
| } | |
| return idx; | |
| }; | |
| }; | |
| /* Polyfill EventEmitter. */ | |
| var EventEmitter = function () { | |
| this.events = {}; | |
| }; | |
| EventEmitter.prototype.on = function (event, listener) { | |
| if (typeof this.events[event] !== 'object') { | |
| this.events[event] = []; | |
| } | |
| this.events[event].push(listener); | |
| }; | |
| EventEmitter.prototype.removeListener = function (event, listener) { | |
| var idx; | |
| if (typeof this.events[event] === 'object') { | |
| idx = indexOf(this.events[event], listener); | |
| if (idx > -1) { | |
| this.events[event].splice(idx, 1); | |
| } | |
| } | |
| }; | |
| EventEmitter.prototype.emit = function (event) { | |
| var i, listeners, length, args = [].slice.call(arguments, 1); | |
| if (typeof this.events[event] === 'object') { | |
| listeners = this.events[event].slice(); | |
| length = listeners.length; | |
| for (i = 0; i < length; i++) { | |
| listeners[i].apply(this, args); | |
| } | |
| } | |
| }; | |
| EventEmitter.prototype.once = function (event, listener) { | |
| this.on(event, function g () { | |
| this.removeListener(event, g); | |
| listener.apply(this, arguments); | |
| }); | |
| }; |
- Modified .on() to add the elements to the start of the array (slower).
- Modified .emit() to loop backwards through the events (much faster). This also avoids the race condition in the relationship between .once() and .emit() as noted by @undecidedapollo up there.
- Modified .removeAllListeners() to take an optional argument to allow the removal of all events associated with a specific name.
In a nutshell...
EventEmitter.prototype.on = function on( name, fn ) {
this.events[name] = [fn].concat( this.events[name] || [] );
}
EventEmitter.prototype.emit = function emit( name, data ) {
for ( let i = this.events[name].length - 1; i >= 0 ; --i ) {
this.events[name][i]( data );
}
}
EventEmitter.prototype.removeAllListeners = function removeAllListeners( name ) {
if ( name ) {
delete this.events[name];
} else {
// drop the old reference
this.events = {};
}
}You can add simple overrides by returning true or false to stop propagation, e.g. return true to stop all other events before it.
// hooks.js
// inspired by gmod lua !
// it is useful to prevent circular dependencies and or import hell
export class hooks {
static register(name, f) {
if (!hooks[name])
hooks[name] = [];
hooks[name].push(f);
return f;
}
static unregister(name, f) {
hooks[name] = hooks[name].filter(e => e != f);
}
static call(name, x) {
if (!hooks[name])
return;
for (let i = hooks[name].length; i--;)
if (hooks[name][i](x))
return;
}
}
export default hooks;Hello, this is actually amazing. What license do you release this under?
This was extracted from my Promise library Pacta and, as such, is released under the BSD 3-clause license.
@undecidedapollo and @coldsilk:
There seems to be a problem with the once/removeListener function. When the event is emitted and the listener is called, it calls remove. The remove function splices the array stored at this.event[eventString] while the emit function is doing a forEach on the same array. This splice modifies the array while it is being iterated against, and causes the forEach to skip the next listener.
It has been a while since I wrote this but I believe this is why emit takes a shallow copy of the list of listeners on line 55 using slice so that the loop is unaffected by removeListener modifying the underlying events.
Come from Pramp. Spent a lot of time figuring out this problem. There is an easier version without once implemented.
Two different ways to implement on and once, be aware of the difference.
Second way: