events.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. 'use strict';
  2. var domain;
  3. // This constructor is used to store event handlers. Instantiating this is
  4. // faster than explicitly calling `Object.create(null)` to get a "clean" empty
  5. // object (tested with v8 v4.9).
  6. function EventHandlers() {}
  7. EventHandlers.prototype = Object.create(null);
  8. function EventEmitter() {
  9. EventEmitter.init.call(this);
  10. }
  11. export default EventEmitter;
  12. export {EventEmitter};
  13. // nodejs oddity
  14. // require('events') === require('events').EventEmitter
  15. EventEmitter.EventEmitter = EventEmitter
  16. EventEmitter.usingDomains = false;
  17. EventEmitter.prototype.domain = undefined;
  18. EventEmitter.prototype._events = undefined;
  19. EventEmitter.prototype._maxListeners = undefined;
  20. // By default EventEmitters will print a warning if more than 10 listeners are
  21. // added to it. This is a useful default which helps finding memory leaks.
  22. EventEmitter.defaultMaxListeners = 10;
  23. EventEmitter.init = function() {
  24. this.domain = null;
  25. if (EventEmitter.usingDomains) {
  26. // if there is an active domain, then attach to it.
  27. if (domain.active && !(this instanceof domain.Domain)) {
  28. this.domain = domain.active;
  29. }
  30. }
  31. if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
  32. this._events = new EventHandlers();
  33. this._eventsCount = 0;
  34. }
  35. this._maxListeners = this._maxListeners || undefined;
  36. };
  37. // Obviously not all Emitters should be limited to 10. This function allows
  38. // that to be increased. Set to zero for unlimited.
  39. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
  40. if (typeof n !== 'number' || n < 0 || isNaN(n))
  41. throw new TypeError('"n" argument must be a positive number');
  42. this._maxListeners = n;
  43. return this;
  44. };
  45. function $getMaxListeners(that) {
  46. if (that._maxListeners === undefined)
  47. return EventEmitter.defaultMaxListeners;
  48. return that._maxListeners;
  49. }
  50. EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
  51. return $getMaxListeners(this);
  52. };
  53. // These standalone emit* functions are used to optimize calling of event
  54. // handlers for fast cases because emit() itself often has a variable number of
  55. // arguments and can be deoptimized because of that. These functions always have
  56. // the same number of arguments and thus do not get deoptimized, so the code
  57. // inside them can execute faster.
  58. function emitNone(handler, isFn, self) {
  59. if (isFn)
  60. handler.call(self);
  61. else {
  62. var len = handler.length;
  63. var listeners = arrayClone(handler, len);
  64. for (var i = 0; i < len; ++i)
  65. listeners[i].call(self);
  66. }
  67. }
  68. function emitOne(handler, isFn, self, arg1) {
  69. if (isFn)
  70. handler.call(self, arg1);
  71. else {
  72. var len = handler.length;
  73. var listeners = arrayClone(handler, len);
  74. for (var i = 0; i < len; ++i)
  75. listeners[i].call(self, arg1);
  76. }
  77. }
  78. function emitTwo(handler, isFn, self, arg1, arg2) {
  79. if (isFn)
  80. handler.call(self, arg1, arg2);
  81. else {
  82. var len = handler.length;
  83. var listeners = arrayClone(handler, len);
  84. for (var i = 0; i < len; ++i)
  85. listeners[i].call(self, arg1, arg2);
  86. }
  87. }
  88. function emitThree(handler, isFn, self, arg1, arg2, arg3) {
  89. if (isFn)
  90. handler.call(self, arg1, arg2, arg3);
  91. else {
  92. var len = handler.length;
  93. var listeners = arrayClone(handler, len);
  94. for (var i = 0; i < len; ++i)
  95. listeners[i].call(self, arg1, arg2, arg3);
  96. }
  97. }
  98. function emitMany(handler, isFn, self, args) {
  99. if (isFn)
  100. handler.apply(self, args);
  101. else {
  102. var len = handler.length;
  103. var listeners = arrayClone(handler, len);
  104. for (var i = 0; i < len; ++i)
  105. listeners[i].apply(self, args);
  106. }
  107. }
  108. EventEmitter.prototype.emit = function emit(type) {
  109. var er, handler, len, args, i, events, domain;
  110. var needDomainExit = false;
  111. var doError = (type === 'error');
  112. events = this._events;
  113. if (events)
  114. doError = (doError && events.error == null);
  115. else if (!doError)
  116. return false;
  117. domain = this.domain;
  118. // If there is no 'error' event listener then throw.
  119. if (doError) {
  120. er = arguments[1];
  121. if (domain) {
  122. if (!er)
  123. er = new Error('Uncaught, unspecified "error" event');
  124. er.domainEmitter = this;
  125. er.domain = domain;
  126. er.domainThrown = false;
  127. domain.emit('error', er);
  128. } else if (er instanceof Error) {
  129. throw er; // Unhandled 'error' event
  130. } else {
  131. // At least give some kind of context to the user
  132. var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
  133. err.context = er;
  134. throw err;
  135. }
  136. return false;
  137. }
  138. handler = events[type];
  139. if (!handler)
  140. return false;
  141. var isFn = typeof handler === 'function';
  142. len = arguments.length;
  143. switch (len) {
  144. // fast cases
  145. case 1:
  146. emitNone(handler, isFn, this);
  147. break;
  148. case 2:
  149. emitOne(handler, isFn, this, arguments[1]);
  150. break;
  151. case 3:
  152. emitTwo(handler, isFn, this, arguments[1], arguments[2]);
  153. break;
  154. case 4:
  155. emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
  156. break;
  157. // slower
  158. default:
  159. args = new Array(len - 1);
  160. for (i = 1; i < len; i++)
  161. args[i - 1] = arguments[i];
  162. emitMany(handler, isFn, this, args);
  163. }
  164. if (needDomainExit)
  165. domain.exit();
  166. return true;
  167. };
  168. function _addListener(target, type, listener, prepend) {
  169. var m;
  170. var events;
  171. var existing;
  172. if (typeof listener !== 'function')
  173. throw new TypeError('"listener" argument must be a function');
  174. events = target._events;
  175. if (!events) {
  176. events = target._events = new EventHandlers();
  177. target._eventsCount = 0;
  178. } else {
  179. // To avoid recursion in the case that type === "newListener"! Before
  180. // adding it to the listeners, first emit "newListener".
  181. if (events.newListener) {
  182. target.emit('newListener', type,
  183. listener.listener ? listener.listener : listener);
  184. // Re-assign `events` because a newListener handler could have caused the
  185. // this._events to be assigned to a new object
  186. events = target._events;
  187. }
  188. existing = events[type];
  189. }
  190. if (!existing) {
  191. // Optimize the case of one listener. Don't need the extra array object.
  192. existing = events[type] = listener;
  193. ++target._eventsCount;
  194. } else {
  195. if (typeof existing === 'function') {
  196. // Adding the second element, need to change to array.
  197. existing = events[type] = prepend ? [listener, existing] :
  198. [existing, listener];
  199. } else {
  200. // If we've already got an array, just append.
  201. if (prepend) {
  202. existing.unshift(listener);
  203. } else {
  204. existing.push(listener);
  205. }
  206. }
  207. // Check for listener leak
  208. if (!existing.warned) {
  209. m = $getMaxListeners(target);
  210. if (m && m > 0 && existing.length > m) {
  211. existing.warned = true;
  212. var w = new Error('Possible EventEmitter memory leak detected. ' +
  213. existing.length + ' ' + type + ' listeners added. ' +
  214. 'Use emitter.setMaxListeners() to increase limit');
  215. w.name = 'MaxListenersExceededWarning';
  216. w.emitter = target;
  217. w.type = type;
  218. w.count = existing.length;
  219. emitWarning(w);
  220. }
  221. }
  222. }
  223. return target;
  224. }
  225. function emitWarning(e) {
  226. typeof console.warn === 'function' ? console.warn(e) : console.log(e);
  227. }
  228. EventEmitter.prototype.addListener = function addListener(type, listener) {
  229. return _addListener(this, type, listener, false);
  230. };
  231. EventEmitter.prototype.on = EventEmitter.prototype.addListener;
  232. EventEmitter.prototype.prependListener =
  233. function prependListener(type, listener) {
  234. return _addListener(this, type, listener, true);
  235. };
  236. function _onceWrap(target, type, listener) {
  237. var fired = false;
  238. function g() {
  239. target.removeListener(type, g);
  240. if (!fired) {
  241. fired = true;
  242. listener.apply(target, arguments);
  243. }
  244. }
  245. g.listener = listener;
  246. return g;
  247. }
  248. EventEmitter.prototype.once = function once(type, listener) {
  249. if (typeof listener !== 'function')
  250. throw new TypeError('"listener" argument must be a function');
  251. this.on(type, _onceWrap(this, type, listener));
  252. return this;
  253. };
  254. EventEmitter.prototype.prependOnceListener =
  255. function prependOnceListener(type, listener) {
  256. if (typeof listener !== 'function')
  257. throw new TypeError('"listener" argument must be a function');
  258. this.prependListener(type, _onceWrap(this, type, listener));
  259. return this;
  260. };
  261. // emits a 'removeListener' event iff the listener was removed
  262. EventEmitter.prototype.removeListener =
  263. function removeListener(type, listener) {
  264. var list, events, position, i, originalListener;
  265. if (typeof listener !== 'function')
  266. throw new TypeError('"listener" argument must be a function');
  267. events = this._events;
  268. if (!events)
  269. return this;
  270. list = events[type];
  271. if (!list)
  272. return this;
  273. if (list === listener || (list.listener && list.listener === listener)) {
  274. if (--this._eventsCount === 0)
  275. this._events = new EventHandlers();
  276. else {
  277. delete events[type];
  278. if (events.removeListener)
  279. this.emit('removeListener', type, list.listener || listener);
  280. }
  281. } else if (typeof list !== 'function') {
  282. position = -1;
  283. for (i = list.length; i-- > 0;) {
  284. if (list[i] === listener ||
  285. (list[i].listener && list[i].listener === listener)) {
  286. originalListener = list[i].listener;
  287. position = i;
  288. break;
  289. }
  290. }
  291. if (position < 0)
  292. return this;
  293. if (list.length === 1) {
  294. list[0] = undefined;
  295. if (--this._eventsCount === 0) {
  296. this._events = new EventHandlers();
  297. return this;
  298. } else {
  299. delete events[type];
  300. }
  301. } else {
  302. spliceOne(list, position);
  303. }
  304. if (events.removeListener)
  305. this.emit('removeListener', type, originalListener || listener);
  306. }
  307. return this;
  308. };
  309. EventEmitter.prototype.removeAllListeners =
  310. function removeAllListeners(type) {
  311. var listeners, events;
  312. events = this._events;
  313. if (!events)
  314. return this;
  315. // not listening for removeListener, no need to emit
  316. if (!events.removeListener) {
  317. if (arguments.length === 0) {
  318. this._events = new EventHandlers();
  319. this._eventsCount = 0;
  320. } else if (events[type]) {
  321. if (--this._eventsCount === 0)
  322. this._events = new EventHandlers();
  323. else
  324. delete events[type];
  325. }
  326. return this;
  327. }
  328. // emit removeListener for all listeners on all events
  329. if (arguments.length === 0) {
  330. var keys = Object.keys(events);
  331. for (var i = 0, key; i < keys.length; ++i) {
  332. key = keys[i];
  333. if (key === 'removeListener') continue;
  334. this.removeAllListeners(key);
  335. }
  336. this.removeAllListeners('removeListener');
  337. this._events = new EventHandlers();
  338. this._eventsCount = 0;
  339. return this;
  340. }
  341. listeners = events[type];
  342. if (typeof listeners === 'function') {
  343. this.removeListener(type, listeners);
  344. } else if (listeners) {
  345. // LIFO order
  346. do {
  347. this.removeListener(type, listeners[listeners.length - 1]);
  348. } while (listeners[0]);
  349. }
  350. return this;
  351. };
  352. EventEmitter.prototype.listeners = function listeners(type) {
  353. var evlistener;
  354. var ret;
  355. var events = this._events;
  356. if (!events)
  357. ret = [];
  358. else {
  359. evlistener = events[type];
  360. if (!evlistener)
  361. ret = [];
  362. else if (typeof evlistener === 'function')
  363. ret = [evlistener.listener || evlistener];
  364. else
  365. ret = unwrapListeners(evlistener);
  366. }
  367. return ret;
  368. };
  369. EventEmitter.listenerCount = function(emitter, type) {
  370. if (typeof emitter.listenerCount === 'function') {
  371. return emitter.listenerCount(type);
  372. } else {
  373. return listenerCount.call(emitter, type);
  374. }
  375. };
  376. EventEmitter.prototype.listenerCount = listenerCount;
  377. function listenerCount(type) {
  378. var events = this._events;
  379. if (events) {
  380. var evlistener = events[type];
  381. if (typeof evlistener === 'function') {
  382. return 1;
  383. } else if (evlistener) {
  384. return evlistener.length;
  385. }
  386. }
  387. return 0;
  388. }
  389. EventEmitter.prototype.eventNames = function eventNames() {
  390. return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
  391. };
  392. // About 1.5x faster than the two-arg version of Array#splice().
  393. function spliceOne(list, index) {
  394. for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
  395. list[i] = list[k];
  396. list.pop();
  397. }
  398. function arrayClone(arr, i) {
  399. var copy = new Array(i);
  400. while (i--)
  401. copy[i] = arr[i];
  402. return copy;
  403. }
  404. function unwrapListeners(arr) {
  405. var ret = new Array(arr.length);
  406. for (var i = 0; i < ret.length; ++i) {
  407. ret[i] = arr[i].listener || arr[i];
  408. }
  409. return ret;
  410. }