not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
8.1 KiB

  1. // Copyright Joyent, Inc. and other Node contributors.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a
  4. // copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to permit
  8. // persons to whom the Software is furnished to do so, subject to the
  9. // following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included
  12. // in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  17. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  18. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. function EventEmitter() {
  22. this._events = this._events || {};
  23. this._maxListeners = this._maxListeners || undefined;
  24. }
  25. // Backwards-compat with node 0.10.x
  26. EventEmitter.EventEmitter = EventEmitter;
  27. EventEmitter.prototype._events = undefined;
  28. EventEmitter.prototype._maxListeners = undefined;
  29. // By default EventEmitters will print a warning if more than 10 listeners are
  30. // added to it. This is a useful default which helps finding memory leaks.
  31. EventEmitter.defaultMaxListeners = 10;
  32. // Obviously not all Emitters should be limited to 10. This function allows
  33. // that to be increased. Set to zero for unlimited.
  34. EventEmitter.prototype.setMaxListeners = function(n) {
  35. if (!isNumber(n) || n < 0 || isNaN(n))
  36. throw TypeError('n must be a positive number');
  37. this._maxListeners = n;
  38. return this;
  39. };
  40. EventEmitter.prototype.emit = function(type) {
  41. var er, handler, len, args, i, listeners;
  42. if (!this._events)
  43. this._events = {};
  44. // If there is no 'error' event listener then throw.
  45. if (type === 'error') {
  46. if (!this._events.error ||
  47. (isObject(this._events.error) && !this._events.error.length)) {
  48. er = arguments[1];
  49. if (er instanceof Error) {
  50. throw er; // Unhandled 'error' event
  51. } else {
  52. // At least give some kind of context to the user
  53. var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
  54. err.context = er;
  55. throw err;
  56. }
  57. }
  58. }
  59. handler = this._events[type];
  60. if (isUndefined(handler))
  61. return false;
  62. if (isFunction(handler)) {
  63. switch (arguments.length) {
  64. // fast cases
  65. case 1:
  66. handler.call(this);
  67. break;
  68. case 2:
  69. handler.call(this, arguments[1]);
  70. break;
  71. case 3:
  72. handler.call(this, arguments[1], arguments[2]);
  73. break;
  74. // slower
  75. default:
  76. args = Array.prototype.slice.call(arguments, 1);
  77. handler.apply(this, args);
  78. }
  79. } else if (isObject(handler)) {
  80. args = Array.prototype.slice.call(arguments, 1);
  81. listeners = handler.slice();
  82. len = listeners.length;
  83. for (i = 0; i < len; i++)
  84. listeners[i].apply(this, args);
  85. }
  86. return true;
  87. };
  88. EventEmitter.prototype.addListener = function(type, listener) {
  89. var m;
  90. if (!isFunction(listener))
  91. throw TypeError('listener must be a function');
  92. if (!this._events)
  93. this._events = {};
  94. // To avoid recursion in the case that type === "newListener"! Before
  95. // adding it to the listeners, first emit "newListener".
  96. if (this._events.newListener)
  97. this.emit('newListener', type,
  98. isFunction(listener.listener) ?
  99. listener.listener : listener);
  100. if (!this._events[type])
  101. // Optimize the case of one listener. Don't need the extra array object.
  102. this._events[type] = listener;
  103. else if (isObject(this._events[type]))
  104. // If we've already got an array, just append.
  105. this._events[type].push(listener);
  106. else
  107. // Adding the second element, need to change to array.
  108. this._events[type] = [this._events[type], listener];
  109. // Check for listener leak
  110. if (isObject(this._events[type]) && !this._events[type].warned) {
  111. if (!isUndefined(this._maxListeners)) {
  112. m = this._maxListeners;
  113. } else {
  114. m = EventEmitter.defaultMaxListeners;
  115. }
  116. if (m && m > 0 && this._events[type].length > m) {
  117. this._events[type].warned = true;
  118. console.error('(node) warning: possible EventEmitter memory ' +
  119. 'leak detected. %d listeners added. ' +
  120. 'Use emitter.setMaxListeners() to increase limit.',
  121. this._events[type].length);
  122. if (typeof console.trace === 'function') {
  123. // not supported in IE 10
  124. console.trace();
  125. }
  126. }
  127. }
  128. return this;
  129. };
  130. EventEmitter.prototype.on = EventEmitter.prototype.addListener;
  131. EventEmitter.prototype.once = function(type, listener) {
  132. if (!isFunction(listener))
  133. throw TypeError('listener must be a function');
  134. var fired = false;
  135. function g() {
  136. this.removeListener(type, g);
  137. if (!fired) {
  138. fired = true;
  139. listener.apply(this, arguments);
  140. }
  141. }
  142. g.listener = listener;
  143. this.on(type, g);
  144. return this;
  145. };
  146. // emits a 'removeListener' event iff the listener was removed
  147. EventEmitter.prototype.removeListener = function(type, listener) {
  148. var list, position, length, i;
  149. if (!isFunction(listener))
  150. throw TypeError('listener must be a function');
  151. if (!this._events || !this._events[type])
  152. return this;
  153. list = this._events[type];
  154. length = list.length;
  155. position = -1;
  156. if (list === listener ||
  157. (isFunction(list.listener) && list.listener === listener)) {
  158. delete this._events[type];
  159. if (this._events.removeListener)
  160. this.emit('removeListener', type, listener);
  161. } else if (isObject(list)) {
  162. for (i = length; i-- > 0;) {
  163. if (list[i] === listener ||
  164. (list[i].listener && list[i].listener === listener)) {
  165. position = i;
  166. break;
  167. }
  168. }
  169. if (position < 0)
  170. return this;
  171. if (list.length === 1) {
  172. list.length = 0;
  173. delete this._events[type];
  174. } else {
  175. list.splice(position, 1);
  176. }
  177. if (this._events.removeListener)
  178. this.emit('removeListener', type, listener);
  179. }
  180. return this;
  181. };
  182. EventEmitter.prototype.removeAllListeners = function(type) {
  183. var key, listeners;
  184. if (!this._events)
  185. return this;
  186. // not listening for removeListener, no need to emit
  187. if (!this._events.removeListener) {
  188. if (arguments.length === 0)
  189. this._events = {};
  190. else if (this._events[type])
  191. delete this._events[type];
  192. return this;
  193. }
  194. // emit removeListener for all listeners on all events
  195. if (arguments.length === 0) {
  196. for (key in this._events) {
  197. if (key === 'removeListener') continue;
  198. this.removeAllListeners(key);
  199. }
  200. this.removeAllListeners('removeListener');
  201. this._events = {};
  202. return this;
  203. }
  204. listeners = this._events[type];
  205. if (isFunction(listeners)) {
  206. this.removeListener(type, listeners);
  207. } else if (listeners) {
  208. // LIFO order
  209. while (listeners.length)
  210. this.removeListener(type, listeners[listeners.length - 1]);
  211. }
  212. delete this._events[type];
  213. return this;
  214. };
  215. EventEmitter.prototype.listeners = function(type) {
  216. var ret;
  217. if (!this._events || !this._events[type])
  218. ret = [];
  219. else if (isFunction(this._events[type]))
  220. ret = [this._events[type]];
  221. else
  222. ret = this._events[type].slice();
  223. return ret;
  224. };
  225. EventEmitter.prototype.listenerCount = function(type) {
  226. if (this._events) {
  227. var evlistener = this._events[type];
  228. if (isFunction(evlistener))
  229. return 1;
  230. else if (evlistener)
  231. return evlistener.length;
  232. }
  233. return 0;
  234. };
  235. EventEmitter.listenerCount = function(emitter, type) {
  236. return emitter.listenerCount(type);
  237. };
  238. function isFunction(arg) {
  239. return typeof arg === 'function';
  240. }
  241. function isNumber(arg) {
  242. return typeof arg === 'number';
  243. }
  244. function isObject(arg) {
  245. return typeof arg === 'object' && arg !== null;
  246. }
  247. function isUndefined(arg) {
  248. return arg === void 0;
  249. }
  250. define(function() {
  251. return EventEmitter
  252. })