• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
22'use strict';
23
24const {
25  Boolean,
26  Error,
27  MathMin,
28  NumberIsNaN,
29  ObjectCreate,
30  ObjectDefineProperty,
31  ObjectGetPrototypeOf,
32  ObjectSetPrototypeOf,
33  Promise,
34  PromiseReject,
35  PromiseResolve,
36  ReflectApply,
37  ReflectOwnKeys,
38  Symbol,
39  SymbolFor,
40  SymbolAsyncIterator
41} = primordials;
42const kRejection = SymbolFor('nodejs.rejection');
43
44let spliceOne;
45
46const {
47  kEnhanceStackBeforeInspector,
48  codes
49} = require('internal/errors');
50const {
51  ERR_INVALID_ARG_TYPE,
52  ERR_OUT_OF_RANGE,
53  ERR_UNHANDLED_ERROR
54} = codes;
55
56const {
57  inspect
58} = require('internal/util/inspect');
59
60const kCapture = Symbol('kCapture');
61const kErrorMonitor = Symbol('events.errorMonitor');
62
63function EventEmitter(opts) {
64  EventEmitter.init.call(this, opts);
65}
66module.exports = EventEmitter;
67module.exports.once = once;
68module.exports.on = on;
69
70// Backwards-compat with node 0.10.x
71EventEmitter.EventEmitter = EventEmitter;
72
73EventEmitter.usingDomains = false;
74
75EventEmitter.captureRejectionSymbol = kRejection;
76ObjectDefineProperty(EventEmitter, 'captureRejections', {
77  get() {
78    return EventEmitter.prototype[kCapture];
79  },
80  set(value) {
81    if (typeof value !== 'boolean') {
82      throw new ERR_INVALID_ARG_TYPE('EventEmitter.captureRejections',
83                                     'boolean', value);
84    }
85
86    EventEmitter.prototype[kCapture] = value;
87  },
88  enumerable: true
89});
90
91EventEmitter.errorMonitor = kErrorMonitor;
92
93// The default for captureRejections is false
94ObjectDefineProperty(EventEmitter.prototype, kCapture, {
95  value: false,
96  writable: true,
97  enumerable: false
98});
99
100EventEmitter.prototype._events = undefined;
101EventEmitter.prototype._eventsCount = 0;
102EventEmitter.prototype._maxListeners = undefined;
103
104// By default EventEmitters will print a warning if more than 10 listeners are
105// added to it. This is a useful default which helps finding memory leaks.
106let defaultMaxListeners = 10;
107
108function checkListener(listener) {
109  if (typeof listener !== 'function') {
110    throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
111  }
112}
113
114ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
115  enumerable: true,
116  get: function() {
117    return defaultMaxListeners;
118  },
119  set: function(arg) {
120    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
121      throw new ERR_OUT_OF_RANGE('defaultMaxListeners',
122                                 'a non-negative number',
123                                 arg);
124    }
125    defaultMaxListeners = arg;
126  }
127});
128
129EventEmitter.init = function(opts) {
130
131  if (this._events === undefined ||
132      this._events === ObjectGetPrototypeOf(this)._events) {
133    this._events = ObjectCreate(null);
134    this._eventsCount = 0;
135  }
136
137  this._maxListeners = this._maxListeners || undefined;
138
139
140  if (opts && opts.captureRejections) {
141    if (typeof opts.captureRejections !== 'boolean') {
142      throw new ERR_INVALID_ARG_TYPE('options.captureRejections',
143                                     'boolean', opts.captureRejections);
144    }
145    this[kCapture] = Boolean(opts.captureRejections);
146  } else {
147    // Assigning the kCapture property directly saves an expensive
148    // prototype lookup in a very sensitive hot path.
149    this[kCapture] = EventEmitter.prototype[kCapture];
150  }
151};
152
153function addCatch(that, promise, type, args) {
154  if (!that[kCapture]) {
155    return;
156  }
157
158  // Handle Promises/A+ spec, then could be a getter
159  // that throws on second use.
160  try {
161    const then = promise.then;
162
163    if (typeof then === 'function') {
164      then.call(promise, undefined, function(err) {
165        // The callback is called with nextTick to avoid a follow-up
166        // rejection from this promise.
167        process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args);
168      });
169    }
170  } catch (err) {
171    that.emit('error', err);
172  }
173}
174
175function emitUnhandledRejectionOrErr(ee, err, type, args) {
176  if (typeof ee[kRejection] === 'function') {
177    ee[kRejection](err, type, ...args);
178  } else {
179    // We have to disable the capture rejections mechanism, otherwise
180    // we might end up in an infinite loop.
181    const prev = ee[kCapture];
182
183    // If the error handler throws, it is not catcheable and it
184    // will end up in 'uncaughtException'. We restore the previous
185    // value of kCapture in case the uncaughtException is present
186    // and the exception is handled.
187    try {
188      ee[kCapture] = false;
189      ee.emit('error', err);
190    } finally {
191      ee[kCapture] = prev;
192    }
193  }
194}
195
196// Obviously not all Emitters should be limited to 10. This function allows
197// that to be increased. Set to zero for unlimited.
198EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
199  if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
200    throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
201  }
202  this._maxListeners = n;
203  return this;
204};
205
206function _getMaxListeners(that) {
207  if (that._maxListeners === undefined)
208    return EventEmitter.defaultMaxListeners;
209  return that._maxListeners;
210}
211
212EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
213  return _getMaxListeners(this);
214};
215
216// Returns the length and line number of the first sequence of `a` that fully
217// appears in `b` with a length of at least 4.
218function identicalSequenceRange(a, b) {
219  for (let i = 0; i < a.length - 3; i++) {
220    // Find the first entry of b that matches the current entry of a.
221    const pos = b.indexOf(a[i]);
222    if (pos !== -1) {
223      const rest = b.length - pos;
224      if (rest > 3) {
225        let len = 1;
226        const maxLen = MathMin(a.length - i, rest);
227        // Count the number of consecutive entries.
228        while (maxLen > len && a[i + len] === b[pos + len]) {
229          len++;
230        }
231        if (len > 3) {
232          return [len, i];
233        }
234      }
235    }
236  }
237
238  return [0, 0];
239}
240
241function enhanceStackTrace(err, own) {
242  let ctorInfo = '';
243  try {
244    const { name } = this.constructor;
245    if (name !== 'EventEmitter')
246      ctorInfo = ` on ${name} instance`;
247  } catch {}
248  const sep = `\nEmitted 'error' event${ctorInfo} at:\n`;
249
250  const errStack = err.stack.split('\n').slice(1);
251  const ownStack = own.stack.split('\n').slice(1);
252
253  const [ len, off ] = identicalSequenceRange(ownStack, errStack);
254  if (len > 0) {
255    ownStack.splice(off + 1, len - 2,
256                    '    [... lines matching original stack trace ...]');
257  }
258
259  return err.stack + sep + ownStack.join('\n');
260}
261
262EventEmitter.prototype.emit = function emit(type, ...args) {
263  let doError = (type === 'error');
264
265  const events = this._events;
266  if (events !== undefined) {
267    if (doError && events[kErrorMonitor] !== undefined)
268      this.emit(kErrorMonitor, ...args);
269    doError = (doError && events.error === undefined);
270  } else if (!doError)
271    return false;
272
273  // If there is no 'error' event listener then throw.
274  if (doError) {
275    let er;
276    if (args.length > 0)
277      er = args[0];
278    if (er instanceof Error) {
279      try {
280        const capture = {};
281        // eslint-disable-next-line no-restricted-syntax
282        Error.captureStackTrace(capture, EventEmitter.prototype.emit);
283        ObjectDefineProperty(er, kEnhanceStackBeforeInspector, {
284          value: enhanceStackTrace.bind(this, er, capture),
285          configurable: true
286        });
287      } catch {}
288
289      // Note: The comments on the `throw` lines are intentional, they show
290      // up in Node's output if this results in an unhandled exception.
291      throw er; // Unhandled 'error' event
292    }
293
294    let stringifiedEr;
295    const { inspect } = require('internal/util/inspect');
296    try {
297      stringifiedEr = inspect(er);
298    } catch {
299      stringifiedEr = er;
300    }
301
302    // At least give some kind of context to the user
303    const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
304    err.context = er;
305    throw err; // Unhandled 'error' event
306  }
307
308  const handler = events[type];
309
310  if (handler === undefined)
311    return false;
312
313  if (typeof handler === 'function') {
314    const result = ReflectApply(handler, this, args);
315
316    // We check if result is undefined first because that
317    // is the most common case so we do not pay any perf
318    // penalty
319    if (result !== undefined && result !== null) {
320      addCatch(this, result, type, args);
321    }
322  } else {
323    const len = handler.length;
324    const listeners = arrayClone(handler);
325    for (let i = 0; i < len; ++i) {
326      const result = ReflectApply(listeners[i], this, args);
327
328      // We check if result is undefined first because that
329      // is the most common case so we do not pay any perf
330      // penalty.
331      // This code is duplicated because extracting it away
332      // would make it non-inlineable.
333      if (result !== undefined && result !== null) {
334        addCatch(this, result, type, args);
335      }
336    }
337  }
338
339  return true;
340};
341
342function _addListener(target, type, listener, prepend) {
343  let m;
344  let events;
345  let existing;
346
347  checkListener(listener);
348
349  events = target._events;
350  if (events === undefined) {
351    events = target._events = ObjectCreate(null);
352    target._eventsCount = 0;
353  } else {
354    // To avoid recursion in the case that type === "newListener"! Before
355    // adding it to the listeners, first emit "newListener".
356    if (events.newListener !== undefined) {
357      target.emit('newListener', type,
358                  listener.listener ? listener.listener : listener);
359
360      // Re-assign `events` because a newListener handler could have caused the
361      // this._events to be assigned to a new object
362      events = target._events;
363    }
364    existing = events[type];
365  }
366
367  if (existing === undefined) {
368    // Optimize the case of one listener. Don't need the extra array object.
369    events[type] = listener;
370    ++target._eventsCount;
371  } else {
372    if (typeof existing === 'function') {
373      // Adding the second element, need to change to array.
374      existing = events[type] =
375        prepend ? [listener, existing] : [existing, listener];
376      // If we've already got an array, just append.
377    } else if (prepend) {
378      existing.unshift(listener);
379    } else {
380      existing.push(listener);
381    }
382
383    // Check for listener leak
384    m = _getMaxListeners(target);
385    if (m > 0 && existing.length > m && !existing.warned) {
386      existing.warned = true;
387      // No error code for this since it is a Warning
388      // eslint-disable-next-line no-restricted-syntax
389      const w = new Error('Possible EventEmitter memory leak detected. ' +
390                          `${existing.length} ${String(type)} listeners ` +
391                          `added to ${inspect(target, { depth: -1 })}. Use ` +
392                          'emitter.setMaxListeners() to increase limit');
393      w.name = 'MaxListenersExceededWarning';
394      w.emitter = target;
395      w.type = type;
396      w.count = existing.length;
397      process.emitWarning(w);
398    }
399  }
400
401  return target;
402}
403
404EventEmitter.prototype.addListener = function addListener(type, listener) {
405  return _addListener(this, type, listener, false);
406};
407
408EventEmitter.prototype.on = EventEmitter.prototype.addListener;
409
410EventEmitter.prototype.prependListener =
411    function prependListener(type, listener) {
412      return _addListener(this, type, listener, true);
413    };
414
415function onceWrapper() {
416  if (!this.fired) {
417    this.target.removeListener(this.type, this.wrapFn);
418    this.fired = true;
419    if (arguments.length === 0)
420      return this.listener.call(this.target);
421    return this.listener.apply(this.target, arguments);
422  }
423}
424
425function _onceWrap(target, type, listener) {
426  const state = { fired: false, wrapFn: undefined, target, type, listener };
427  const wrapped = onceWrapper.bind(state);
428  wrapped.listener = listener;
429  state.wrapFn = wrapped;
430  return wrapped;
431}
432
433EventEmitter.prototype.once = function once(type, listener) {
434  checkListener(listener);
435
436  this.on(type, _onceWrap(this, type, listener));
437  return this;
438};
439
440EventEmitter.prototype.prependOnceListener =
441    function prependOnceListener(type, listener) {
442      checkListener(listener);
443
444      this.prependListener(type, _onceWrap(this, type, listener));
445      return this;
446    };
447
448// Emits a 'removeListener' event if and only if the listener was removed.
449EventEmitter.prototype.removeListener =
450    function removeListener(type, listener) {
451      checkListener(listener);
452
453      const events = this._events;
454      if (events === undefined)
455        return this;
456
457      const list = events[type];
458      if (list === undefined)
459        return this;
460
461      if (list === listener || list.listener === listener) {
462        if (--this._eventsCount === 0)
463          this._events = ObjectCreate(null);
464        else {
465          delete events[type];
466          if (events.removeListener)
467            this.emit('removeListener', type, list.listener || listener);
468        }
469      } else if (typeof list !== 'function') {
470        let position = -1;
471
472        for (let i = list.length - 1; i >= 0; i--) {
473          if (list[i] === listener || list[i].listener === listener) {
474            position = i;
475            break;
476          }
477        }
478
479        if (position < 0)
480          return this;
481
482        if (position === 0)
483          list.shift();
484        else {
485          if (spliceOne === undefined)
486            spliceOne = require('internal/util').spliceOne;
487          spliceOne(list, position);
488        }
489
490        if (list.length === 1)
491          events[type] = list[0];
492
493        if (events.removeListener !== undefined)
494          this.emit('removeListener', type, listener);
495      }
496
497      return this;
498    };
499
500EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
501
502EventEmitter.prototype.removeAllListeners =
503    function removeAllListeners(type) {
504      const events = this._events;
505      if (events === undefined)
506        return this;
507
508      // Not listening for removeListener, no need to emit
509      if (events.removeListener === undefined) {
510        if (arguments.length === 0) {
511          this._events = ObjectCreate(null);
512          this._eventsCount = 0;
513        } else if (events[type] !== undefined) {
514          if (--this._eventsCount === 0)
515            this._events = ObjectCreate(null);
516          else
517            delete events[type];
518        }
519        return this;
520      }
521
522      // Emit removeListener for all listeners on all events
523      if (arguments.length === 0) {
524        for (const key of ReflectOwnKeys(events)) {
525          if (key === 'removeListener') continue;
526          this.removeAllListeners(key);
527        }
528        this.removeAllListeners('removeListener');
529        this._events = ObjectCreate(null);
530        this._eventsCount = 0;
531        return this;
532      }
533
534      const listeners = events[type];
535
536      if (typeof listeners === 'function') {
537        this.removeListener(type, listeners);
538      } else if (listeners !== undefined) {
539        // LIFO order
540        for (let i = listeners.length - 1; i >= 0; i--) {
541          this.removeListener(type, listeners[i]);
542        }
543      }
544
545      return this;
546    };
547
548function _listeners(target, type, unwrap) {
549  const events = target._events;
550
551  if (events === undefined)
552    return [];
553
554  const evlistener = events[type];
555  if (evlistener === undefined)
556    return [];
557
558  if (typeof evlistener === 'function')
559    return unwrap ? [evlistener.listener || evlistener] : [evlistener];
560
561  return unwrap ?
562    unwrapListeners(evlistener) : arrayClone(evlistener);
563}
564
565EventEmitter.prototype.listeners = function listeners(type) {
566  return _listeners(this, type, true);
567};
568
569EventEmitter.prototype.rawListeners = function rawListeners(type) {
570  return _listeners(this, type, false);
571};
572
573EventEmitter.listenerCount = function(emitter, type) {
574  if (typeof emitter.listenerCount === 'function') {
575    return emitter.listenerCount(type);
576  }
577  return listenerCount.call(emitter, type);
578};
579
580EventEmitter.prototype.listenerCount = listenerCount;
581function listenerCount(type) {
582  const events = this._events;
583
584  if (events !== undefined) {
585    const evlistener = events[type];
586
587    if (typeof evlistener === 'function') {
588      return 1;
589    } else if (evlistener !== undefined) {
590      return evlistener.length;
591    }
592  }
593
594  return 0;
595}
596
597EventEmitter.prototype.eventNames = function eventNames() {
598  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
599};
600
601function arrayClone(arr) {
602  // At least since V8 8.3, this implementation is faster than the previous
603  // which always used a simple for-loop
604  switch (arr.length) {
605    case 2: return [arr[0], arr[1]];
606    case 3: return [arr[0], arr[1], arr[2]];
607    case 4: return [arr[0], arr[1], arr[2], arr[3]];
608    case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]];
609    case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]];
610  }
611  return arr.slice();
612}
613
614function unwrapListeners(arr) {
615  const ret = arrayClone(arr);
616  for (let i = 0; i < ret.length; ++i) {
617    const orig = ret[i].listener;
618    if (typeof orig === 'function')
619      ret[i] = orig;
620  }
621  return ret;
622}
623
624function once(emitter, name) {
625  return new Promise((resolve, reject) => {
626    if (
627      typeof emitter.addEventListener === 'function' &&
628      typeof emitter.on !== 'function'
629    ) {
630      // EventTarget does not have `error` event semantics like Node
631      // EventEmitters, we do not listen to `error` events here.
632      emitter.addEventListener(
633        name,
634        (...args) => { resolve(args); },
635        { once: true }
636      );
637      return;
638    }
639
640    const eventListener = (...args) => {
641      if (errorListener !== undefined) {
642        emitter.removeListener('error', errorListener);
643      }
644      resolve(args);
645    };
646    let errorListener;
647
648    // Adding an error listener is not optional because
649    // if an error is thrown on an event emitter we cannot
650    // guarantee that the actual event we are waiting will
651    // be fired. The result could be a silent way to create
652    // memory or file descriptor leaks, which is something
653    // we should avoid.
654    if (name !== 'error') {
655      errorListener = (err) => {
656        emitter.removeListener(name, eventListener);
657        reject(err);
658      };
659
660      emitter.once('error', errorListener);
661    }
662
663    emitter.once(name, eventListener);
664  });
665}
666
667const AsyncIteratorPrototype = ObjectGetPrototypeOf(
668  ObjectGetPrototypeOf(async function* () {}).prototype);
669
670function createIterResult(value, done) {
671  return { value, done };
672}
673
674function on(emitter, event) {
675  const unconsumedEvents = [];
676  const unconsumedPromises = [];
677  let error = null;
678  let finished = false;
679
680  const iterator = ObjectSetPrototypeOf({
681    next() {
682      // First, we consume all unread events
683      const value = unconsumedEvents.shift();
684      if (value) {
685        return PromiseResolve(createIterResult(value, false));
686      }
687
688      // Then we error, if an error happened
689      // This happens one time if at all, because after 'error'
690      // we stop listening
691      if (error) {
692        const p = PromiseReject(error);
693        // Only the first element errors
694        error = null;
695        return p;
696      }
697
698      // If the iterator is finished, resolve to done
699      if (finished) {
700        return PromiseResolve(createIterResult(undefined, true));
701      }
702
703      // Wait until an event happens
704      return new Promise(function(resolve, reject) {
705        unconsumedPromises.push({ resolve, reject });
706      });
707    },
708
709    return() {
710      emitter.removeListener(event, eventHandler);
711      emitter.removeListener('error', errorHandler);
712      finished = true;
713
714      for (const promise of unconsumedPromises) {
715        promise.resolve(createIterResult(undefined, true));
716      }
717
718      return PromiseResolve(createIterResult(undefined, true));
719    },
720
721    throw(err) {
722      if (!err || !(err instanceof Error)) {
723        throw new ERR_INVALID_ARG_TYPE('EventEmitter.AsyncIterator',
724                                       'Error', err);
725      }
726      error = err;
727      emitter.removeListener(event, eventHandler);
728      emitter.removeListener('error', errorHandler);
729    },
730
731    [SymbolAsyncIterator]() {
732      return this;
733    }
734  }, AsyncIteratorPrototype);
735
736  emitter.on(event, eventHandler);
737  emitter.on('error', errorHandler);
738
739  return iterator;
740
741  function eventHandler(...args) {
742    const promise = unconsumedPromises.shift();
743    if (promise) {
744      promise.resolve(createIterResult(args, false));
745    } else {
746      unconsumedEvents.push(args);
747    }
748  }
749
750  function errorHandler(err) {
751    finished = true;
752
753    const toError = unconsumedPromises.shift();
754
755    if (toError) {
756      toError.reject(err);
757    } else {
758      // The next time we call next()
759      error = err;
760    }
761
762    iterator.return();
763  }
764}
765