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