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