Created
August 15, 2012 21:51
-
-
Save Olical/3364020 to your computer and use it in GitHub Desktop.
Snapshot of EventEmitter 3 and 4 to be used in jsPerf: Test case URL will be http://jsperf.com/eventemitter-3-vs-4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* EventEmitter v3.1.7 | |
* https://github.com/Wolfy87/EventEmitter | |
* | |
* Oliver Caldwell (http://oli.me.uk) | |
* Creative Commons Attribution 3.0 Unported License (http://creativecommons.org/licenses/by/3.0/) | |
*/ | |
;(function(exports) { | |
// JSHint config | |
/*jshint devel:true*/ | |
/*global define:true*/ | |
// Place the script into strict mode | |
'use strict'; | |
/** | |
* EventEmitter class | |
* Creates an object with event registering and firing methods | |
*/ | |
function EventEmitter() { | |
// Initialise required storage variables | |
this._events = {}; | |
this._maxListeners = 10; | |
} | |
/** | |
* Event class | |
* Contains Event methods and property storage | |
* | |
* @param {String} type Event type name | |
* @param {Function} listener Function to be called when the event is fired | |
* @param {Object} scope Object that this should be set to when the listener is called | |
* @param {Boolean} once If true then the listener will be removed after the first call | |
* @param {Object} instance The parent EventEmitter instance | |
*/ | |
function Event(type, listener, scope, once, instance) { | |
// Store arguments | |
this.type = type; | |
this.listener = listener; | |
this.scope = scope; | |
this.once = once; | |
this.instance = instance; | |
} | |
/** | |
* Executes the listener | |
* | |
* @param {Array} args List of arguments to pass to the listener | |
* @return {Boolean} If false then it was a once event | |
*/ | |
Event.prototype.fire = function(args) { | |
this.listener.apply(this.scope || this.instance, args); | |
// Remove the listener if this is a once only listener | |
if(this.once) { | |
// By storing the original value we can make sure it was actually removed | |
// There was a bug in which you would get an infinite loop if you called removeAllListeners from a once event | |
// By doing this if the event is lost it will not make the loop go back one | |
var original = this.instance.listeners(this.type).length; | |
this.instance.removeListener(this.type, this.listener, this.scope); | |
// Only return false if the length has changed | |
// This is a fix for issue #26 | |
if(original !== this.instance.listeners(this.type).length) { | |
return false; | |
} | |
} | |
}; | |
/** | |
* Passes every listener for a specified event to a function one at a time | |
* | |
* @param {String} type Event type name | |
* @param {Function} callback Function to pass each listener to | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.eachListener = function(type, callback) { | |
// Initialise variables | |
var i = null, | |
possibleListeners = null, | |
result = null; | |
// Only loop if the type exists | |
if(this._events.hasOwnProperty(type)) { | |
possibleListeners = this._events[type]; | |
for(i = 0; i < possibleListeners.length; i += 1) { | |
result = callback.call(this, possibleListeners[i], i); | |
if(result === false) { | |
i -= 1; | |
} | |
else if(result === true) { | |
break; | |
} | |
} | |
} | |
// Return the instance to allow chaining | |
return this; | |
}; | |
/** | |
* Adds an event listener for the specified event | |
* | |
* @param {String} type Event type name | |
* @param {Function} listener Function to be called when the event is fired | |
* @param {Object} scope Object that this should be set to when the listener is called | |
* @param {Boolean} once If true then the listener will be removed after the first call | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.addListener = function(type, listener, scope, once) { | |
// Create the listener array if it does not exist yet | |
if(!this._events.hasOwnProperty(type)) { | |
this._events[type] = []; | |
} | |
// Push the new event to the array | |
this._events[type].push(new Event(type, listener, scope, once, this)); | |
// Emit the new listener event | |
this.emit('newListener', type, listener, scope, once); | |
// Check if we have exceeded the maxListener count | |
// Ignore this check if the count is 0 | |
// Also don't check if we have already fired a warning | |
if(this._maxListeners && !this._events[type].warned && this._events[type].length > this._maxListeners) { | |
// The max listener count has been exceeded! | |
// Warn via the console if it exists | |
if(typeof console !== 'undefined') { | |
console.warn('Possible EventEmitter memory leak detected. ' + this._events[type].length + ' listeners added. Use emitter.setMaxListeners() to increase limit.'); | |
} | |
// Set the flag so it doesn't fire again | |
this._events[type].warned = true; | |
} | |
// Return the instance to allow chaining | |
return this; | |
}; | |
/** | |
* Alias of the addListener method | |
* | |
* @param {String} type Event type name | |
* @param {Function} listener Function to be called when the event is fired | |
* @param {Object} scope Object that this should be set to when the listener is called | |
* @param {Boolean} once If true then the listener will be removed after the first call | |
*/ | |
EventEmitter.prototype.on = EventEmitter.prototype.addListener; | |
/** | |
* Alias of the addListener method but will remove the event after the first use | |
* | |
* @param {String} type Event type name | |
* @param {Function} listener Function to be called when the event is fired | |
* @param {Object} scope Object that this should be set to when the listener is called | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.once = function(type, listener, scope) { | |
return this.addListener(type, listener, scope, true); | |
}; | |
/** | |
* Removes the a listener for the specified event | |
* | |
* @param {String} type Event type name the listener must have for the event to be removed | |
* @param {Function} listener Listener the event must have to be removed | |
* @param {Object} scope The scope the event must have to be removed | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.removeListener = function(type, listener, scope) { | |
this.eachListener(type, function(currentListener, index) { | |
// If this is the listener remove it from the array | |
// We also compare the scope if it was passed | |
if(currentListener.listener === listener && (!scope || currentListener.scope === scope)) { | |
this._events[type].splice(index, 1); | |
} | |
}); | |
// Remove the property if there are no more listeners | |
if(this._events[type] && this._events[type].length === 0) { | |
delete this._events[type]; | |
} | |
// Return the instance to allow chaining | |
return this; | |
}; | |
/** | |
* Alias of the removeListener method | |
* | |
* @param {String} type Event type name the listener must have for the event to be removed | |
* @param {Function} listener Listener the event must have to be removed | |
* @param {Object} scope The scope the event must have to be removed | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.off = EventEmitter.prototype.removeListener; | |
/** | |
* Removes all listeners for a specified event | |
* If no event type is passed it will remove every listener | |
* | |
* @param {String} type Event type name to remove all listeners from | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.removeAllListeners = function(type) { | |
// Check for a type, if there is none remove all listeners | |
// If there is a type however, just remove the listeners for that type | |
if(type && this._events.hasOwnProperty(type)) { | |
delete this._events[type]; | |
} | |
else if(!type) { | |
this._events = {}; | |
} | |
// Return the instance to allow chaining | |
return this; | |
}; | |
/** | |
* Retrieves the array of listeners for a specified event | |
* | |
* @param {String} type Event type name to return all listeners from | |
* @return {Array} Will return either an array of listeners or an empty array if there are none | |
*/ | |
EventEmitter.prototype.listeners = function(type) { | |
// Return the array of listeners or an empty array if it does not exist | |
if(this._events.hasOwnProperty(type)) { | |
// It does exist, loop over building the array | |
var listeners = []; | |
this.eachListener(type, function(evt) { | |
listeners.push(evt.listener); | |
}); | |
return listeners; | |
} | |
return []; | |
}; | |
/** | |
* Emits an event executing all appropriate listeners | |
* All values passed after the type will be passed as arguments to the listeners | |
* | |
* @param {String} type Event type name to run all listeners from | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.emit = function(type) { | |
// Calculate the arguments | |
var args = [], | |
i = null; | |
for(i = 1; i < arguments.length; i += 1) { | |
args.push(arguments[i]); | |
} | |
this.eachListener(type, function(currentListener) { | |
return currentListener.fire(args); | |
}); | |
// Return the instance to allow chaining | |
return this; | |
}; | |
/** | |
* Sets the max listener count for the EventEmitter | |
* When the count of listeners for an event exceeds this limit a warning will be printed | |
* Set to 0 for no limit | |
* | |
* @param {Number} maxListeners The new max listener limit | |
* @return {Object} The current EventEmitter instance to allow chaining | |
*/ | |
EventEmitter.prototype.setMaxListeners = function(maxListeners) { | |
this._maxListeners = maxListeners; | |
// Return the instance to allow chaining | |
return this; | |
}; | |
/** | |
* Builds a clone of the prototype object for you to extend with | |
* | |
* @return {Object} A clone of the EventEmitter prototype object | |
*/ | |
EventEmitter.extend = function() { | |
// First thing we need to do is create our new prototype | |
// Then we loop over the current one copying each method out | |
// When done, simply return the clone | |
var clone = {}, | |
current = this.prototype, | |
key = null; | |
for(key in current) { | |
// Make sure this is actually a property of the object before copying it | |
// We don't want any default object methods leaking though | |
if(current.hasOwnProperty(key)) { | |
clone[key] = current[key]; | |
} | |
} | |
// All done, return the clone | |
return clone; | |
}; | |
// Export the class | |
// If AMD is available then use it | |
if(typeof define === 'function' && define.amd) { | |
define(function() { | |
return EventEmitter; | |
}); | |
} | |
// No matter what it will be added to the global object | |
exports.EventEmitter3 = EventEmitter; | |
}(this)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* EventEmitter v4.0.0 - github.com/Wolfy87/EventEmitter | |
* Oliver Caldwell | |
* MIT license | |
*/ | |
;(function(exports) { | |
// JSHint config - http://www.jshint.com/ | |
/*global define:true*/ | |
// Place the script in strict mode | |
'use strict'; | |
/** | |
* Class for managing events. | |
* Can be extended to provide event functionality in other classes. | |
* | |
* @class Manages event registering and emitting. | |
*/ | |
function EventEmitter(){} | |
/** | |
* Provides a shortcut to the prototype. | |
* | |
* @property {Object} Shortcut to the prototype object. | |
*/ | |
EventEmitter.fn = EventEmitter.prototype; | |
/** | |
* Returns the listener array for the specified event. | |
* Will initialise the event object and listener arrays if required. | |
* | |
* @param {String} evt Name of the event to return the listeners from. | |
* @returns {Function[]} All listener functions for the event. | |
*/ | |
EventEmitter.fn.getListeners = function(evt) { | |
// Create a shortcut to the storage object | |
// Initialise it if it does not exists yet | |
var events = this._events || (this._events = {}); | |
// Return the listener array | |
// Initialise it if it does not exist | |
return events[evt] || (events[evt] = []); | |
}; | |
/** | |
* Finds the index of the listener for the event in it's storage array | |
* | |
* @param {Function} listener Method to look for. | |
* @param {Function[]} listeners Array of listeners to search through. | |
* @returns {Number} Index of the specified listener, -1 if not found | |
*/ | |
EventEmitter.fn.indexOfListener = function(listener, listeners) { | |
// Return the index via the native method if possible | |
if(listeners.indexOf) { | |
return listeners.indexOf(listener); | |
} | |
// There is no native method | |
// Use a manual loop to find the index | |
var i = listeners.length; | |
while(i--) { | |
// If the listener matches, return it's index | |
if(listeners[i] === listener) { | |
return i; | |
} | |
} | |
// Default to returning -1 | |
return -1; | |
}; | |
/** | |
* Adds a listener function to the specified event. | |
* The listener will not be added if it is a duplicate. | |
* | |
* @param {String} evt Name of the event to attach the listener to. | |
* @param {Function} listener Method to be called when the event is emitted. | |
* @returns {Object} Current instance of EventEmitter for chaining. | |
*/ | |
EventEmitter.fn.addListener = function(evt, listener) { | |
// Fetch the listeners | |
var listeners = this.getListeners(evt); | |
// Push the listener into the array if it is not already there | |
if(this.indexOfListener(listener, listeners) === -1) { | |
listeners.push(listener); | |
} | |
// Return the instance of EventEmitter to allow chaining | |
return this; | |
}; | |
/** | |
* Removes a listener function from the specified event. | |
* | |
* @param {String} evt Name of the event to remove the listener from. | |
* @param {Function} listener Method to remove from the event. | |
* @returns {Object} Current instance of EventEmitter for chaining. | |
*/ | |
EventEmitter.fn.removeListener = function(evt, listener) { | |
// Fetch the listeners | |
// And get the index of the listener in the array | |
var listeners = this.getListeners(evt), | |
index = this.indexOfListener(listener, listeners); | |
// If the listener was found then remove it | |
if(index !== -1) { | |
listeners.splice(index, 1); | |
// If there are no more listeners in this array then remove it | |
if(listeners.length === 0) { | |
delete this._events[evt]; | |
} | |
} | |
// Return the instance of EventEmitter to allow chaining | |
return this; | |
}; | |
/** | |
* Removes all listeners from a specified event. | |
* If you do not specify an event then all listeners will be removed. | |
* That means every event will be emptied. | |
* | |
* @param {String} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. | |
* @returns {Object} Current instance of EventEmitter for chaining. | |
*/ | |
EventEmitter.fn.removeListeners = function(evt) { | |
// Remove different things depending on the state of evt | |
if(evt) { | |
// Remove all listeners for the specified event | |
delete this._events[evt]; | |
} | |
else { | |
// Remove all listeners in all events | |
delete this._events; | |
} | |
// Return the instance of EventEmitter to allow chaining | |
return this; | |
}; | |
/** | |
* Emits an event of your choice. | |
* When emitted, every listener attached to that event will be executed. | |
* If you pass the optional argument array then those arguments will be passed to every listener upon execution. | |
* Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. | |
* So they will not arrive within the array on the other side, they will be separate. | |
* | |
* @param {String} evt Name of the event to emit and execute listeners for. | |
* @param {Array} [args] Optional array of arguments to be passed to each argument. | |
* @returns {Object} Current instance of EventEmitter for chaining. | |
*/ | |
EventEmitter.fn.emitEvent = function(evt, args) { | |
// Get the listeners for the event | |
// Also initialise any other required variables | |
var listeners = this.getListeners(evt), | |
i = listeners.length; | |
// Make args default to an empty array | |
args = args || []; | |
while(i--) { | |
// Execute every listener attached to the event | |
// Apply the arguments array to each listener too | |
listeners[i].apply(null, args); | |
} | |
// Return the instance of EventEmitter to allow chaining | |
return this; | |
}; | |
// Expose the class either via AMD or the global object | |
if(typeof define === 'function' && define.amd) { | |
define(function() { | |
return EventEmitter; | |
}); | |
} | |
else { | |
exports.EventEmitter4 = EventEmitter; | |
} | |
}(this)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment