sequential_executor.js (7145B)
1 var AWS = require('./core'); 2 3 /** 4 * @api private 5 * @!method on(eventName, callback) 6 * Registers an event listener callback for the event given by `eventName`. 7 * Parameters passed to the callback function depend on the individual event 8 * being triggered. See the event documentation for those parameters. 9 * 10 * @param eventName [String] the event name to register the listener for 11 * @param callback [Function] the listener callback function 12 * @return [AWS.SequentialExecutor] the same object for chaining 13 */ 14 AWS.SequentialExecutor = AWS.util.inherit({ 15 16 constructor: function SequentialExecutor() { 17 this._events = {}; 18 }, 19 20 /** 21 * @api private 22 */ 23 listeners: function listeners(eventName) { 24 return this._events[eventName] ? this._events[eventName].slice(0) : []; 25 }, 26 27 on: function on(eventName, listener) { 28 if (this._events[eventName]) { 29 this._events[eventName].push(listener); 30 } else { 31 this._events[eventName] = [listener]; 32 } 33 return this; 34 }, 35 36 /** 37 * @api private 38 */ 39 onAsync: function onAsync(eventName, listener) { 40 listener._isAsync = true; 41 return this.on(eventName, listener); 42 }, 43 44 removeListener: function removeListener(eventName, listener) { 45 var listeners = this._events[eventName]; 46 if (listeners) { 47 var length = listeners.length; 48 var position = -1; 49 for (var i = 0; i < length; ++i) { 50 if (listeners[i] === listener) { 51 position = i; 52 } 53 } 54 if (position > -1) { 55 listeners.splice(position, 1); 56 } 57 } 58 return this; 59 }, 60 61 removeAllListeners: function removeAllListeners(eventName) { 62 if (eventName) { 63 delete this._events[eventName]; 64 } else { 65 this._events = {}; 66 } 67 return this; 68 }, 69 70 /** 71 * @api private 72 */ 73 emit: function emit(eventName, eventArgs, doneCallback) { 74 if (!doneCallback) doneCallback = function() { }; 75 var listeners = this.listeners(eventName); 76 var count = listeners.length; 77 this.callListeners(listeners, eventArgs, doneCallback); 78 return count > 0; 79 }, 80 81 /** 82 * @api private 83 */ 84 callListeners: function callListeners(listeners, args, doneCallback, prevError) { 85 var self = this; 86 var error = prevError || null; 87 88 function callNextListener(err) { 89 if (err) { 90 error = AWS.util.error(error || new Error(), err); 91 if (self._haltHandlersOnError) { 92 return doneCallback.call(self, error); 93 } 94 } 95 self.callListeners(listeners, args, doneCallback, error); 96 } 97 98 while (listeners.length > 0) { 99 var listener = listeners.shift(); 100 if (listener._isAsync) { // asynchronous listener 101 listener.apply(self, args.concat([callNextListener])); 102 return; // stop here, callNextListener will continue 103 } else { // synchronous listener 104 try { 105 listener.apply(self, args); 106 } catch (err) { 107 error = AWS.util.error(error || new Error(), err); 108 } 109 if (error && self._haltHandlersOnError) { 110 doneCallback.call(self, error); 111 return; 112 } 113 } 114 } 115 doneCallback.call(self, error); 116 }, 117 118 /** 119 * Adds or copies a set of listeners from another list of 120 * listeners or SequentialExecutor object. 121 * 122 * @param listeners [map<String,Array<Function>>, AWS.SequentialExecutor] 123 * a list of events and callbacks, or an event emitter object 124 * containing listeners to add to this emitter object. 125 * @return [AWS.SequentialExecutor] the emitter object, for chaining. 126 * @example Adding listeners from a map of listeners 127 * emitter.addListeners({ 128 * event1: [function() { ... }, function() { ... }], 129 * event2: [function() { ... }] 130 * }); 131 * emitter.emit('event1'); // emitter has event1 132 * emitter.emit('event2'); // emitter has event2 133 * @example Adding listeners from another emitter object 134 * var emitter1 = new AWS.SequentialExecutor(); 135 * emitter1.on('event1', function() { ... }); 136 * emitter1.on('event2', function() { ... }); 137 * var emitter2 = new AWS.SequentialExecutor(); 138 * emitter2.addListeners(emitter1); 139 * emitter2.emit('event1'); // emitter2 has event1 140 * emitter2.emit('event2'); // emitter2 has event2 141 */ 142 addListeners: function addListeners(listeners) { 143 var self = this; 144 145 // extract listeners if parameter is an SequentialExecutor object 146 if (listeners._events) listeners = listeners._events; 147 148 AWS.util.each(listeners, function(event, callbacks) { 149 if (typeof callbacks === 'function') callbacks = [callbacks]; 150 AWS.util.arrayEach(callbacks, function(callback) { 151 self.on(event, callback); 152 }); 153 }); 154 155 return self; 156 }, 157 158 /** 159 * Registers an event with {on} and saves the callback handle function 160 * as a property on the emitter object using a given `name`. 161 * 162 * @param name [String] the property name to set on this object containing 163 * the callback function handle so that the listener can be removed in 164 * the future. 165 * @param (see on) 166 * @return (see on) 167 * @example Adding a named listener DATA_CALLBACK 168 * var listener = function() { doSomething(); }; 169 * emitter.addNamedListener('DATA_CALLBACK', 'data', listener); 170 * 171 * // the following prints: true 172 * console.log(emitter.DATA_CALLBACK == listener); 173 */ 174 addNamedListener: function addNamedListener(name, eventName, callback) { 175 this[name] = callback; 176 this.addListener(eventName, callback); 177 return this; 178 }, 179 180 /** 181 * @api private 182 */ 183 addNamedAsyncListener: function addNamedAsyncListener(name, eventName, callback) { 184 callback._isAsync = true; 185 return this.addNamedListener(name, eventName, callback); 186 }, 187 188 /** 189 * Helper method to add a set of named listeners using 190 * {addNamedListener}. The callback contains a parameter 191 * with a handle to the `addNamedListener` method. 192 * 193 * @callback callback function(add) 194 * The callback function is called immediately in order to provide 195 * the `add` function to the block. This simplifies the addition of 196 * a large group of named listeners. 197 * @param add [Function] the {addNamedListener} function to call 198 * when registering listeners. 199 * @example Adding a set of named listeners 200 * emitter.addNamedListeners(function(add) { 201 * add('DATA_CALLBACK', 'data', function() { ... }); 202 * add('OTHER', 'otherEvent', function() { ... }); 203 * add('LAST', 'lastEvent', function() { ... }); 204 * }); 205 * 206 * // these properties are now set: 207 * emitter.DATA_CALLBACK; 208 * emitter.OTHER; 209 * emitter.LAST; 210 */ 211 addNamedListeners: function addNamedListeners(callback) { 212 var self = this; 213 callback( 214 function() { 215 self.addNamedListener.apply(self, arguments); 216 }, 217 function() { 218 self.addNamedAsyncListener.apply(self, arguments); 219 } 220 ); 221 return this; 222 } 223 }); 224 225 /** 226 * {on} is the prefered method. 227 * @api private 228 */ 229 AWS.SequentialExecutor.prototype.addListener = AWS.SequentialExecutor.prototype.on; 230 231 module.exports = AWS.SequentialExecutor;