236 lines
7.2 KiB
JavaScript
236 lines
7.2 KiB
JavaScript
|
var AWS = require('./core');
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
* @!method on(eventName, callback)
|
||
|
* Registers an event listener callback for the event given by `eventName`.
|
||
|
* Parameters passed to the callback function depend on the individual event
|
||
|
* being triggered. See the event documentation for those parameters.
|
||
|
*
|
||
|
* @param eventName [String] the event name to register the listener for
|
||
|
* @param callback [Function] the listener callback function
|
||
|
* @param toHead [Boolean] attach the listener callback to the head of callback array if set to true.
|
||
|
* Default to be false.
|
||
|
* @return [AWS.SequentialExecutor] the same object for chaining
|
||
|
*/
|
||
|
AWS.SequentialExecutor = AWS.util.inherit({
|
||
|
|
||
|
constructor: function SequentialExecutor() {
|
||
|
this._events = {};
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
listeners: function listeners(eventName) {
|
||
|
return this._events[eventName] ? this._events[eventName].slice(0) : [];
|
||
|
},
|
||
|
|
||
|
on: function on(eventName, listener, toHead) {
|
||
|
if (this._events[eventName]) {
|
||
|
toHead ?
|
||
|
this._events[eventName].unshift(listener) :
|
||
|
this._events[eventName].push(listener);
|
||
|
} else {
|
||
|
this._events[eventName] = [listener];
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
onAsync: function onAsync(eventName, listener, toHead) {
|
||
|
listener._isAsync = true;
|
||
|
return this.on(eventName, listener, toHead);
|
||
|
},
|
||
|
|
||
|
removeListener: function removeListener(eventName, listener) {
|
||
|
var listeners = this._events[eventName];
|
||
|
if (listeners) {
|
||
|
var length = listeners.length;
|
||
|
var position = -1;
|
||
|
for (var i = 0; i < length; ++i) {
|
||
|
if (listeners[i] === listener) {
|
||
|
position = i;
|
||
|
}
|
||
|
}
|
||
|
if (position > -1) {
|
||
|
listeners.splice(position, 1);
|
||
|
}
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
removeAllListeners: function removeAllListeners(eventName) {
|
||
|
if (eventName) {
|
||
|
delete this._events[eventName];
|
||
|
} else {
|
||
|
this._events = {};
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
emit: function emit(eventName, eventArgs, doneCallback) {
|
||
|
if (!doneCallback) doneCallback = function() { };
|
||
|
var listeners = this.listeners(eventName);
|
||
|
var count = listeners.length;
|
||
|
this.callListeners(listeners, eventArgs, doneCallback);
|
||
|
return count > 0;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
callListeners: function callListeners(listeners, args, doneCallback, prevError) {
|
||
|
var self = this;
|
||
|
var error = prevError || null;
|
||
|
|
||
|
function callNextListener(err) {
|
||
|
if (err) {
|
||
|
error = AWS.util.error(error || new Error(), err);
|
||
|
if (self._haltHandlersOnError) {
|
||
|
return doneCallback.call(self, error);
|
||
|
}
|
||
|
}
|
||
|
self.callListeners(listeners, args, doneCallback, error);
|
||
|
}
|
||
|
|
||
|
while (listeners.length > 0) {
|
||
|
var listener = listeners.shift();
|
||
|
if (listener._isAsync) { // asynchronous listener
|
||
|
listener.apply(self, args.concat([callNextListener]));
|
||
|
return; // stop here, callNextListener will continue
|
||
|
} else { // synchronous listener
|
||
|
try {
|
||
|
listener.apply(self, args);
|
||
|
} catch (err) {
|
||
|
error = AWS.util.error(error || new Error(), err);
|
||
|
}
|
||
|
if (error && self._haltHandlersOnError) {
|
||
|
doneCallback.call(self, error);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
doneCallback.call(self, error);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Adds or copies a set of listeners from another list of
|
||
|
* listeners or SequentialExecutor object.
|
||
|
*
|
||
|
* @param listeners [map<String,Array<Function>>, AWS.SequentialExecutor]
|
||
|
* a list of events and callbacks, or an event emitter object
|
||
|
* containing listeners to add to this emitter object.
|
||
|
* @return [AWS.SequentialExecutor] the emitter object, for chaining.
|
||
|
* @example Adding listeners from a map of listeners
|
||
|
* emitter.addListeners({
|
||
|
* event1: [function() { ... }, function() { ... }],
|
||
|
* event2: [function() { ... }]
|
||
|
* });
|
||
|
* emitter.emit('event1'); // emitter has event1
|
||
|
* emitter.emit('event2'); // emitter has event2
|
||
|
* @example Adding listeners from another emitter object
|
||
|
* var emitter1 = new AWS.SequentialExecutor();
|
||
|
* emitter1.on('event1', function() { ... });
|
||
|
* emitter1.on('event2', function() { ... });
|
||
|
* var emitter2 = new AWS.SequentialExecutor();
|
||
|
* emitter2.addListeners(emitter1);
|
||
|
* emitter2.emit('event1'); // emitter2 has event1
|
||
|
* emitter2.emit('event2'); // emitter2 has event2
|
||
|
*/
|
||
|
addListeners: function addListeners(listeners) {
|
||
|
var self = this;
|
||
|
|
||
|
// extract listeners if parameter is an SequentialExecutor object
|
||
|
if (listeners._events) listeners = listeners._events;
|
||
|
|
||
|
AWS.util.each(listeners, function(event, callbacks) {
|
||
|
if (typeof callbacks === 'function') callbacks = [callbacks];
|
||
|
AWS.util.arrayEach(callbacks, function(callback) {
|
||
|
self.on(event, callback);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
return self;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Registers an event with {on} and saves the callback handle function
|
||
|
* as a property on the emitter object using a given `name`.
|
||
|
*
|
||
|
* @param name [String] the property name to set on this object containing
|
||
|
* the callback function handle so that the listener can be removed in
|
||
|
* the future.
|
||
|
* @param (see on)
|
||
|
* @return (see on)
|
||
|
* @example Adding a named listener DATA_CALLBACK
|
||
|
* var listener = function() { doSomething(); };
|
||
|
* emitter.addNamedListener('DATA_CALLBACK', 'data', listener);
|
||
|
*
|
||
|
* // the following prints: true
|
||
|
* console.log(emitter.DATA_CALLBACK == listener);
|
||
|
*/
|
||
|
addNamedListener: function addNamedListener(name, eventName, callback, toHead) {
|
||
|
this[name] = callback;
|
||
|
this.addListener(eventName, callback, toHead);
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
addNamedAsyncListener: function addNamedAsyncListener(name, eventName, callback, toHead) {
|
||
|
callback._isAsync = true;
|
||
|
return this.addNamedListener(name, eventName, callback, toHead);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Helper method to add a set of named listeners using
|
||
|
* {addNamedListener}. The callback contains a parameter
|
||
|
* with a handle to the `addNamedListener` method.
|
||
|
*
|
||
|
* @callback callback function(add)
|
||
|
* The callback function is called immediately in order to provide
|
||
|
* the `add` function to the block. This simplifies the addition of
|
||
|
* a large group of named listeners.
|
||
|
* @param add [Function] the {addNamedListener} function to call
|
||
|
* when registering listeners.
|
||
|
* @example Adding a set of named listeners
|
||
|
* emitter.addNamedListeners(function(add) {
|
||
|
* add('DATA_CALLBACK', 'data', function() { ... });
|
||
|
* add('OTHER', 'otherEvent', function() { ... });
|
||
|
* add('LAST', 'lastEvent', function() { ... });
|
||
|
* });
|
||
|
*
|
||
|
* // these properties are now set:
|
||
|
* emitter.DATA_CALLBACK;
|
||
|
* emitter.OTHER;
|
||
|
* emitter.LAST;
|
||
|
*/
|
||
|
addNamedListeners: function addNamedListeners(callback) {
|
||
|
var self = this;
|
||
|
callback(
|
||
|
function() {
|
||
|
self.addNamedListener.apply(self, arguments);
|
||
|
},
|
||
|
function() {
|
||
|
self.addNamedAsyncListener.apply(self, arguments);
|
||
|
}
|
||
|
);
|
||
|
return this;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* {on} is the prefered method.
|
||
|
* @api private
|
||
|
*/
|
||
|
AWS.SequentialExecutor.prototype.addListener = AWS.SequentialExecutor.prototype.on;
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
module.exports = AWS.SequentialExecutor;
|