Skip to main content
Deno 2 is finally here 🎉️
Learn more
Module

std/node/_events.js

Deno standard library
Go to Latest
The Standard Library has been moved to JSR. See the blog post for details.
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.// Copyright Joyent, Inc. and other Node contributors.//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the// "Software"), to deal in the Software without restriction, including// without limitation the rights to use, copy, modify, merge, publish,// distribute, sublicense, and/or sell copies of the Software, and to permit// persons to whom the Software is furnished to do so, subject to the// following conditions://// The above copyright notice and this permission notice shall be included// in all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const kRejection = Symbol.for("nodejs.rejection");
import { inspect } from "./internal/util/inspect.js";import { AbortError, // kEnhanceStackBeforeInspector, ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE, ERR_UNHANDLED_ERROR,} from "./internal/errors.ts";
import { validateAbortSignal, validateBoolean, validateFunction,} from "./internal/validators.js";import { spliceOne } from "./_utils.ts";
const kCapture = Symbol("kCapture");const kErrorMonitor = Symbol("events.errorMonitor");const kMaxEventTargetListeners = Symbol("events.maxEventTargetListeners");const kMaxEventTargetListenersWarned = Symbol( "events.maxEventTargetListenersWarned",);
/** * Creates a new `EventEmitter` instance. * @param {{ captureRejections?: boolean; }} [opts] * @returns {EventEmitter} */export function EventEmitter(opts) { EventEmitter.init.call(this, opts);}export default EventEmitter;EventEmitter.on = on;EventEmitter.once = once;EventEmitter.getEventListeners = getEventListeners;// Backwards-compat with node 0.10.xEventEmitter.EventEmitter = EventEmitter;EventEmitter.usingDomains = false;
EventEmitter.captureRejectionSymbol = kRejection;export const captureRejectionSymbol = EventEmitter.captureRejectionSymbol;export const errorMonitor = EventEmitter.errorMonitor;
Object.defineProperty(EventEmitter, "captureRejections", { get() { return EventEmitter.prototype[kCapture]; }, set(value) { validateBoolean(value, "EventEmitter.captureRejections");
EventEmitter.prototype[kCapture] = value; }, enumerable: true,});
EventEmitter.errorMonitor = kErrorMonitor;
// The default for captureRejections is falseObject.defineProperty(EventEmitter.prototype, kCapture, { value: false, writable: true, enumerable: false,});
EventEmitter.prototype._events = undefined;EventEmitter.prototype._eventsCount = 0;EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are// added to it. This is a useful default which helps finding memory leaks.export let defaultMaxListeners = 10;let isEventTarget;
function checkListener(listener) { validateFunction(listener, "listener");}
Object.defineProperty(EventEmitter, "defaultMaxListeners", { enumerable: true, get: function () { return defaultMaxListeners; }, set: function (arg) { if (typeof arg !== "number" || arg < 0 || Number.isNaN(arg)) { throw new ERR_OUT_OF_RANGE( "defaultMaxListeners", "a non-negative number", arg, ); } defaultMaxListeners = arg; },});
Object.defineProperties(EventEmitter, { kMaxEventTargetListeners: { value: kMaxEventTargetListeners, enumerable: false, configurable: false, writable: false, }, kMaxEventTargetListenersWarned: { value: kMaxEventTargetListenersWarned, enumerable: false, configurable: false, writable: false, },});
/** * Sets the max listeners. * @param {number} n * @param {EventTarget[] | EventEmitter[]} [eventTargets] * @returns {void} */EventEmitter.setMaxListeners = function ( n = defaultMaxListeners, ...eventTargets) { if (typeof n !== "number" || n < 0 || Number.isNaN(n)) { throw new ERR_OUT_OF_RANGE("n", "a non-negative number", n); } if (eventTargets.length === 0) { defaultMaxListeners = n; } else { if (isEventTarget === undefined) { isEventTarget = require("internal/event_target").isEventTarget; }
for (let i = 0; i < eventTargets.length; i++) { const target = eventTargets[i]; if (isEventTarget(target)) { target[kMaxEventTargetListeners] = n; target[kMaxEventTargetListenersWarned] = false; } else if (typeof target.setMaxListeners === "function") { target.setMaxListeners(n); } else { throw new ERR_INVALID_ARG_TYPE( "eventTargets", ["EventEmitter", "EventTarget"], target, ); } } }};
EventEmitter.init = function (opts) { if ( this._events === undefined || this._events === Object.getPrototypeOf(this)._events ) { this._events = Object.create(null); this._eventsCount = 0; }
this._maxListeners = this._maxListeners || undefined;
if (opts?.captureRejections) { validateBoolean(opts.captureRejections, "options.captureRejections"); this[kCapture] = Boolean(opts.captureRejections); } else { // Assigning the kCapture property directly saves an expensive // prototype lookup in a very sensitive hot path. this[kCapture] = EventEmitter.prototype[kCapture]; }};
function addCatch(that, promise, type, args) { if (!that[kCapture]) { return; }
// Handle Promises/A+ spec, then could be a getter // that throws on second use. try { const then = promise.then;
if (typeof then === "function") { then.call(promise, undefined, function (err) { // The callback is called with nextTick to avoid a follow-up // rejection from this promise. process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args); }); } } catch (err) { that.emit("error", err); }}
function emitUnhandledRejectionOrErr(ee, err, type, args) { if (typeof ee[kRejection] === "function") { ee[kRejection](err, type, ...args); } else { // We have to disable the capture rejections mechanism, otherwise // we might end up in an infinite loop. const prev = ee[kCapture];
// If the error handler throws, it is not catcheable and it // will end up in 'uncaughtException'. We restore the previous // value of kCapture in case the uncaughtException is present // and the exception is handled. try { ee[kCapture] = false; ee.emit("error", err); } finally { ee[kCapture] = prev; } }}
/** * Increases the max listeners of the event emitter. * @param {number} n * @returns {EventEmitter} */EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== "number" || n < 0 || Number.isNaN(n)) { throw new ERR_OUT_OF_RANGE("n", "a non-negative number", n); } this._maxListeners = n; return this;};
function _getMaxListeners(that) { if (that._maxListeners === undefined) { return EventEmitter.defaultMaxListeners; } return that._maxListeners;}
/** * Returns the current max listener value for the event emitter. * @returns {number} */EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this);};
// Returns the length and line number of the first sequence of `a` that fully// appears in `b` with a length of at least 4.function identicalSequenceRange(a, b) { for (let i = 0; i < a.length - 3; i++) { // Find the first entry of b that matches the current entry of a. const pos = b.indexOf(a[i]); if (pos !== -1) { const rest = b.length - pos; if (rest > 3) { let len = 1; const maxLen = Math.min(a.length - i, rest); // Count the number of consecutive entries. while (maxLen > len && a[i + len] === b[pos + len]) { len++; } if (len > 3) { return [len, i]; } } } }
return [0, 0];}
// deno-lint-ignore no-unused-varsfunction enhanceStackTrace(err, own) { let ctorInfo = ""; try { const { name } = this.constructor; if (name !== "EventEmitter") { ctorInfo = ` on ${name} instance`; } } catch { // pass } const sep = `\nEmitted 'error' event${ctorInfo} at:\n`;
const errStack = err.stack.split("\n").slice(1); const ownStack = own.stack.split("\n").slice(1);
const { 0: len, 1: off } = identicalSequenceRange(ownStack, errStack); if (len > 0) { ownStack.splice( off + 1, len - 2, " [... lines matching original stack trace ...]", ); }
return err.stack + sep + ownStack.join("\n");}
/** * Synchronously calls each of the listeners registered * for the event. * @param {string | symbol} type * @param {...any} [args] * @returns {boolean} */EventEmitter.prototype.emit = function emit(type, ...args) { let doError = (type === "error");
const events = this._events; if (events !== undefined) { if (doError && events[kErrorMonitor] !== undefined) { this.emit(kErrorMonitor, ...args); } doError = doError && events.error === undefined; } else if (!doError) { return false; }
// If there is no 'error' event listener then throw. if (doError) { let er; if (args.length > 0) { er = args[0]; } if (er instanceof Error) { try { const capture = {}; Error.captureStackTrace(capture, EventEmitter.prototype.emit); // Object.defineProperty(er, kEnhanceStackBeforeInspector, { // value: enhanceStackTrace.bind(this, er, capture), // configurable: true // }); } catch { // pass }
// Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event }
let stringifiedEr; try { stringifiedEr = inspect(er); } catch { stringifiedEr = er; }
// At least give some kind of context to the user const err = new ERR_UNHANDLED_ERROR(stringifiedEr); err.context = er; throw err; // Unhandled 'error' event }
const handler = events[type];
if (handler === undefined) { return false; }
if (typeof handler === "function") { const result = handler.apply(this, args);
// We check if result is undefined first because that // is the most common case so we do not pay any perf // penalty if (result !== undefined && result !== null) { addCatch(this, result, type, args); } } else { const len = handler.length; const listeners = arrayClone(handler); for (let i = 0; i < len; ++i) { const result = listeners[i].apply(this, args);
// We check if result is undefined first because that // is the most common case so we do not pay any perf // penalty. // This code is duplicated because extracting it away // would make it non-inlineable. if (result !== undefined && result !== null) { addCatch(this, result, type, args); } } }
return true;};
function _addListener(target, type, listener, prepend) { let m; let events; let existing;
checkListener(listener);
events = target._events; if (events === undefined) { events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit("newListener", type, listener.listener ?? listener);
// Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; }
if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. events[type] = listener; ++target._eventsCount; } else { if (typeof existing === "function") { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); }
// Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax const w = new Error( "Possible EventEmitter memory leak detected. " + `${existing.length} ${String(type)} listeners ` + `added to ${inspect(target, { depth: -1 })}. Use ` + "emitter.setMaxListeners() to increase limit", ); w.name = "MaxListenersExceededWarning"; w.emitter = target; w.type = type; w.count = existing.length; process.emitWarning(w); } }
return target;}
/** * Adds a listener to the event emitter. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false);};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
/** * Adds the `listener` function to the beginning of * the listeners array. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */EventEmitter.prototype.prependListener = function prependListener( type, listener,) { return _addListener(this, type, listener, true);};
function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) { return this.listener.call(this.target); } return this.listener.apply(this.target, arguments); }}
function _onceWrap(target, type, listener) { const state = { fired: false, wrapFn: undefined, target, type, listener }; const wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped;}
/** * Adds a one-time `listener` function to the event emitter. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */EventEmitter.prototype.once = function once(type, listener) { checkListener(listener);
this.on(type, _onceWrap(this, type, listener)); return this;};
/** * Adds a one-time `listener` function to the beginning of * the listeners array. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */EventEmitter.prototype.prependOnceListener = function prependOnceListener( type, listener,) { checkListener(listener);
this.prependListener(type, _onceWrap(this, type, listener)); return this;};
/** * Removes the specified `listener` from the listeners array. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */EventEmitter.prototype.removeListener = function removeListener( type, listener,) { checkListener(listener);
const events = this._events; if (events === undefined) { return this; }
const list = events[type]; if (list === undefined) { return this; }
if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) { this._events = Object.create(null); } else { delete events[type]; if (events.removeListener) { this.emit("removeListener", type, list.listener || listener); } } } else if (typeof list !== "function") { let position = -1;
for (let i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { position = i; break; } }
if (position < 0) { return this; }
if (position === 0) { list.shift(); } else { spliceOne(list, position); }
if (list.length === 1) { events[type] = list[0]; }
if (events.removeListener !== undefined) { this.emit("removeListener", type, listener); } }
return this;};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
/** * Removes all listeners from the event emitter. (Only * removes listeners for a specific event name if specified * as `type`). * @param {string | symbol} [type] * @returns {EventEmitter} */EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { const events = this._events; if (events === undefined) { return this; }
// Not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) { this._events = Object.create(null); } else { delete events[type]; } } return this; }
// Emit removeListener for all listeners on all events if (arguments.length === 0) { for (const key of Reflect.ownKeys(events)) { if (key === "removeListener") continue; this.removeAllListeners(key); } this.removeAllListeners("removeListener"); this._events = Object.create(null); this._eventsCount = 0; return this; }
const listeners = events[type];
if (typeof listeners === "function") { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (let i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } }
return this;};
function _listeners(target, type, unwrap) { const events = target._events;
if (events === undefined) { return []; }
const evlistener = events[type]; if (evlistener === undefined) { return []; }
if (typeof evlistener === "function") { return unwrap ? [evlistener.listener || evlistener] : [evlistener]; }
return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener);}
/** * Returns a copy of the array of listeners for the event name * specified as `type`. * @param {string | symbol} type * @returns {Function[]} */EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true);};
/** * Returns a copy of the array of listeners and wrappers for * the event name specified as `type`. * @param {string | symbol} type * @returns {Function[]} */EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false);};
/** * Returns the number of listeners listening to the event name * specified as `type`. * @deprecated since v3.2.0 * @param {EventEmitter} emitter * @param {string | symbol} type * @returns {number} */EventEmitter.listenerCount = function (emitter, type) { if (typeof emitter.listenerCount === "function") { return emitter.listenerCount(type); } return listenerCount.call(emitter, type);};
EventEmitter.prototype.listenerCount = listenerCount;
/** * Returns the number of listeners listening to event name * specified as `type`. * @param {string | symbol} type * @returns {number} */function listenerCount(type) { const events = this._events;
if (events !== undefined) { const evlistener = events[type];
if (typeof evlistener === "function") { return 1; } else if (evlistener !== undefined) { return evlistener.length; } }
return 0;}
/** * Returns an array listing the events for which * the emitter has registered listeners. * @returns {any[]} */EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];};
function arrayClone(arr) { // At least since V8 8.3, this implementation is faster than the previous // which always used a simple for-loop switch (arr.length) { case 2: return [arr[0], arr[1]]; case 3: return [arr[0], arr[1], arr[2]]; case 4: return [arr[0], arr[1], arr[2], arr[3]]; case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]]; case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]]; } return arr.slice();}
function unwrapListeners(arr) { const ret = arrayClone(arr); for (let i = 0; i < ret.length; ++i) { const orig = ret[i].listener; if (typeof orig === "function") { ret[i] = orig; } } return ret;}
/** * Returns a copy of the array of listeners for the event name * specified as `type`. * @param {EventEmitter | EventTarget} emitterOrTarget * @param {string | symbol} type * @returns {Function[]} */export function getEventListeners(emitterOrTarget, type) { // First check if EventEmitter if (typeof emitterOrTarget.listeners === "function") { return emitterOrTarget.listeners(type); } // Require event target lazily to avoid always loading it const { isEventTarget, kEvents } = require("internal/event_target"); if (isEventTarget(emitterOrTarget)) { const root = emitterOrTarget[kEvents].get(type); const listeners = []; let handler = root?.next; while (handler?.listener !== undefined) { const listener = handler.listener?.deref ? handler.listener.deref() : handler.listener; listeners.push(listener); handler = handler.next; } return listeners; } throw new ERR_INVALID_ARG_TYPE( "emitter", ["EventEmitter", "EventTarget"], emitterOrTarget, );}
/** * Creates a `Promise` that is fulfilled when the emitter * emits the given event. * @param {EventEmitter} emitter * @param {string} name * @param {{ signal: AbortSignal; }} [options] * @returns {Promise} */// deno-lint-ignore require-awaitexport async function once(emitter, name, options = {}) { const signal = options?.signal; validateAbortSignal(signal, "options.signal"); if (signal?.aborted) { throw new AbortError(); } return new Promise((resolve, reject) => { const errorListener = (err) => { emitter.removeListener(name, resolver); if (signal != null) { eventTargetAgnosticRemoveListener(signal, "abort", abortListener); } reject(err); }; const resolver = (...args) => { if (typeof emitter.removeListener === "function") { emitter.removeListener("error", errorListener); } if (signal != null) { eventTargetAgnosticRemoveListener(signal, "abort", abortListener); } resolve(args); }; eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== "error" && typeof emitter.once === "function") { emitter.once("error", errorListener); } function abortListener() { eventTargetAgnosticRemoveListener(emitter, name, resolver); eventTargetAgnosticRemoveListener(emitter, "error", errorListener); reject(new AbortError()); } if (signal != null) { eventTargetAgnosticAddListener( signal, "abort", abortListener, { once: true }, ); } });}
const AsyncIteratorPrototype = Object.getPrototypeOf( Object.getPrototypeOf(async function* () {}).prototype,);
function createIterResult(value, done) { return { value, done };}
function eventTargetAgnosticRemoveListener(emitter, name, listener, flags) { if (typeof emitter.removeListener === "function") { emitter.removeListener(name, listener); } else if (typeof emitter.removeEventListener === "function") { emitter.removeEventListener(name, listener, flags); } else { throw new ERR_INVALID_ARG_TYPE("emitter", "EventEmitter", emitter); }}
function eventTargetAgnosticAddListener(emitter, name, listener, flags) { if (typeof emitter.on === "function") { if (flags?.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === "function") { // EventTarget does not have `error` event semantics like Node // EventEmitters, we do not listen to `error` events here. emitter.addEventListener(name, (arg) => { listener(arg); }, flags); } else { throw new ERR_INVALID_ARG_TYPE("emitter", "EventEmitter", emitter); }}
/** * Returns an `AsyncIterator` that iterates `event` events. * @param {EventEmitter} emitter * @param {string | symbol} event * @param {{ signal: AbortSignal; }} [options] * @returns {AsyncIterator} */export function on(emitter, event, options) { const signal = options?.signal; validateAbortSignal(signal, "options.signal"); if (signal?.aborted) { throw new AbortError(); }
const unconsumedEvents = []; const unconsumedPromises = []; let error = null; let finished = false;
const iterator = Object.setPrototypeOf({ next() { // First, we consume all unread events const value = unconsumedEvents.shift(); if (value) { return Promise.resolve(createIterResult(value, false)); }
// Then we error, if an error happened // This happens one time if at all, because after 'error' // we stop listening if (error) { const p = Promise.reject(error); // Only the first element errors error = null; return p; }
// If the iterator is finished, resolve to done if (finished) { return Promise.resolve(createIterResult(undefined, true)); }
// Wait until an event happens return new Promise(function (resolve, reject) { unconsumedPromises.push({ resolve, reject }); }); },
return() { eventTargetAgnosticRemoveListener(emitter, event, eventHandler); eventTargetAgnosticRemoveListener(emitter, "error", errorHandler);
if (signal) { eventTargetAgnosticRemoveListener( signal, "abort", abortListener, { once: true }, ); }
finished = true;
for (const promise of unconsumedPromises) { promise.resolve(createIterResult(undefined, true)); }
return Promise.resolve(createIterResult(undefined, true)); },
throw(err) { if (!err || !(err instanceof Error)) { throw new ERR_INVALID_ARG_TYPE( "EventEmitter.AsyncIterator", "Error", err, ); } error = err; eventTargetAgnosticRemoveListener(emitter, event, eventHandler); eventTargetAgnosticRemoveListener(emitter, "error", errorHandler); },
[Symbol.asyncIterator]() { return this; }, }, AsyncIteratorPrototype);
eventTargetAgnosticAddListener(emitter, event, eventHandler); if (event !== "error" && typeof emitter.on === "function") { emitter.on("error", errorHandler); }
if (signal) { eventTargetAgnosticAddListener( signal, "abort", abortListener, { once: true }, ); }
return iterator;
function abortListener() { errorHandler(new AbortError()); }
function eventHandler(...args) { const promise = unconsumedPromises.shift(); if (promise) { promise.resolve(createIterResult(args, false)); } else { unconsumedEvents.push(args); } }
function errorHandler(err) { finished = true;
const toError = unconsumedPromises.shift();
if (toError) { toError.reject(err); } else { // The next time we call next() error = err; }
iterator.return(); }}