diff options
author | Guy Bedford <guybedford@gmail.com> | 2020-11-09 06:25:13 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-09 09:25:13 -0500 |
commit | 8b7f5531ee1ccde897e87890e9aabc554fedb9dd (patch) | |
tree | 117a85b98d1488c290d8acc392cfb99b1b21f8e0 /std/node/events.ts | |
parent | 293cae5e1ff2a5768e2f3a73cc18f99acc3fbfbd (diff) |
feat(std/node): consistent Node.js builtin shapes (#8274)
Diffstat (limited to 'std/node/events.ts')
-rw-r--r-- | std/node/events.ts | 316 |
1 files changed, 164 insertions, 152 deletions
diff --git a/std/node/events.ts b/std/node/events.ts index 568393f7f..16790907e 100644 --- a/std/node/events.ts +++ b/std/node/events.ts @@ -31,12 +31,36 @@ export interface WrappedFunction extends Function { listener: GenericFunction; } +// deno-lint-ignore no-explicit-any +function createIterResult(value: any, done: boolean): IteratorResult<any> { + return { value, done }; +} + +interface AsyncIterable { + // deno-lint-ignore no-explicit-any + next(): Promise<IteratorResult<any, any>>; + // deno-lint-ignore no-explicit-any + return(): Promise<IteratorResult<any, any>>; + throw(err: Error): void; + // deno-lint-ignore no-explicit-any + [Symbol.asyncIterator](): any; +} + +export let defaultMaxListeners = 10; + /** * See also https://nodejs.org/api/events.html */ export default class EventEmitter { - public static defaultMaxListeners = 10; + public static captureRejectionSymbol = Symbol.for("nodejs.rejection"); public static errorMonitor = Symbol("events.errorMonitor"); + public static get defaultMaxListeners() { + return defaultMaxListeners; + } + public static set defaultMaxListeners(value: number) { + defaultMaxListeners = value; + } + private maxListeners: number | undefined; private _events: Map< string | symbol, @@ -367,180 +391,168 @@ export default class EventEmitter { this.maxListeners = n; return this; } -} -export { EventEmitter }; - -/** - * Creates a Promise that is fulfilled when the EventEmitter emits the given - * event or that is rejected when the EventEmitter emits 'error'. The Promise - * will resolve with an array of all the arguments emitted to the given event. - */ -export function once( - emitter: EventEmitter | EventTarget, - name: string, - // deno-lint-ignore no-explicit-any -): Promise<any[]> { - return new Promise((resolve, reject) => { - if (emitter instanceof EventTarget) { - // EventTarget does not have `error` event semantics like Node - // EventEmitters, we do not listen to `error` events here. - emitter.addEventListener( - name, - (...args) => { - resolve(args); - }, - { once: true, passive: false, capture: false }, - ); - return; - } else if (emitter instanceof EventEmitter) { - // deno-lint-ignore no-explicit-any - const eventListener = (...args: any[]): void => { - if (errorListener !== undefined) { - emitter.removeListener("error", errorListener); - } - resolve(args); - }; - let errorListener: GenericFunction; - - // Adding an error listener is not optional because - // if an error is thrown on an event emitter we cannot - // guarantee that the actual event we are waiting will - // be fired. The result could be a silent way to create - // memory or file descriptor leaks, which is something - // we should avoid. - if (name !== "error") { + /** + * Creates a Promise that is fulfilled when the EventEmitter emits the given + * event or that is rejected when the EventEmitter emits 'error'. The Promise + * will resolve with an array of all the arguments emitted to the given event. + */ + public static once( + emitter: EventEmitter | EventTarget, + name: string, + // deno-lint-ignore no-explicit-any + ): Promise<any[]> { + return new Promise((resolve, reject) => { + if (emitter instanceof EventTarget) { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen to `error` events here. + emitter.addEventListener( + name, + (...args) => { + resolve(args); + }, + { once: true, passive: false, capture: false }, + ); + return; + } else if (emitter instanceof EventEmitter) { // deno-lint-ignore no-explicit-any - errorListener = (err: any): void => { - emitter.removeListener(name, eventListener); - reject(err); + const eventListener = (...args: any[]): void => { + if (errorListener !== undefined) { + emitter.removeListener("error", errorListener); + } + resolve(args); }; + let errorListener: GenericFunction; + + // Adding an error listener is not optional because + // if an error is thrown on an event emitter we cannot + // guarantee that the actual event we are waiting will + // be fired. The result could be a silent way to create + // memory or file descriptor leaks, which is something + // we should avoid. + if (name !== "error") { + // deno-lint-ignore no-explicit-any + errorListener = (err: any): void => { + emitter.removeListener(name, eventListener); + reject(err); + }; + + emitter.once("error", errorListener); + } - emitter.once("error", errorListener); + emitter.once(name, eventListener); + return; } + }); + } - emitter.once(name, eventListener); - return; - } - }); -} + /** + * Returns an AsyncIterator that iterates eventName events. It will throw if + * the EventEmitter emits 'error'. It removes all listeners when exiting the + * loop. The value returned by each iteration is an array composed of the + * emitted event arguments. + */ + public static on( + emitter: EventEmitter, + event: string | symbol, + ): AsyncIterable { + // deno-lint-ignore no-explicit-any + const unconsumedEventValues: any[] = []; + // deno-lint-ignore no-explicit-any + const unconsumedPromises: any[] = []; + let error: Error | null = null; + let finished = false; -// deno-lint-ignore no-explicit-any -function createIterResult(value: any, done: boolean): IteratorResult<any> { - return { value, done }; -} + const iterator = { + // deno-lint-ignore no-explicit-any + next(): Promise<IteratorResult<any>> { + // First, we consume all unread events + // deno-lint-ignore no-explicit-any + const value: any = unconsumedEventValues.shift(); + if (value) { + return Promise.resolve(createIterResult(value, false)); + } -interface AsyncInterable { - // deno-lint-ignore no-explicit-any - next(): Promise<IteratorResult<any, any>>; - // deno-lint-ignore no-explicit-any - return(): Promise<IteratorResult<any, any>>; - throw(err: Error): void; - // deno-lint-ignore no-explicit-any - [Symbol.asyncIterator](): any; -} + // 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<never> = Promise.reject(error); + // Only the first element errors + error = null; + return p; + } -/** - * Returns an AsyncIterator that iterates eventName events. It will throw if - * the EventEmitter emits 'error'. It removes all listeners when exiting the - * loop. The value returned by each iteration is an array composed of the - * emitted event arguments. - */ -export function on( - emitter: EventEmitter, - event: string | symbol, -): AsyncInterable { - // deno-lint-ignore no-explicit-any - const unconsumedEventValues: any[] = []; - // deno-lint-ignore no-explicit-any - const unconsumedPromises: any[] = []; - let error: Error | null = null; - let finished = false; + // 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 }); + }); + }, - const iterator = { - // deno-lint-ignore no-explicit-any - next(): Promise<IteratorResult<any>> { - // First, we consume all unread events // deno-lint-ignore no-explicit-any - const value: any = unconsumedEventValues.shift(); - if (value) { - return Promise.resolve(createIterResult(value, false)); - } + return(): Promise<IteratorResult<any>> { + emitter.removeListener(event, eventHandler); + emitter.removeListener("error", errorHandler); + finished = true; - // 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<never> = Promise.reject(error); - // Only the first element errors - error = null; - return p; - } + for (const promise of unconsumedPromises) { + promise.resolve(createIterResult(undefined, true)); + } - // 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 }); - }); - }, + }, - // deno-lint-ignore no-explicit-any - return(): Promise<IteratorResult<any>> { - emitter.removeListener(event, eventHandler); - emitter.removeListener("error", errorHandler); - finished = true; + throw(err: Error): void { + error = err; + emitter.removeListener(event, eventHandler); + emitter.removeListener("error", errorHandler); + }, - for (const promise of unconsumedPromises) { - promise.resolve(createIterResult(undefined, true)); - } + // deno-lint-ignore no-explicit-any + [Symbol.asyncIterator](): any { + return this; + }, + }; - return Promise.resolve(createIterResult(undefined, true)); - }, + emitter.on(event, eventHandler); + emitter.on("error", errorHandler); - throw(err: Error): void { - error = err; - emitter.removeListener(event, eventHandler); - emitter.removeListener("error", errorHandler); - }, + return iterator; // deno-lint-ignore no-explicit-any - [Symbol.asyncIterator](): any { - return this; - }, - }; - - emitter.on(event, eventHandler); - emitter.on("error", errorHandler); - - return iterator; - - // deno-lint-ignore no-explicit-any - function eventHandler(...args: any[]): void { - const promise = unconsumedPromises.shift(); - if (promise) { - promise.resolve(createIterResult(args, false)); - } else { - unconsumedEventValues.push(args); + function eventHandler(...args: any[]): void { + const promise = unconsumedPromises.shift(); + if (promise) { + promise.resolve(createIterResult(args, false)); + } else { + unconsumedEventValues.push(args); + } } - } - // deno-lint-ignore no-explicit-any - function errorHandler(err: any): void { - finished = true; + // deno-lint-ignore no-explicit-any + function errorHandler(err: any): void { + finished = true; - const toError = unconsumedPromises.shift(); - if (toError) { - toError.reject(err); - } else { - // The next time we call next() - error = err; - } + const toError = unconsumedPromises.shift(); + if (toError) { + toError.reject(err); + } else { + // The next time we call next() + error = err; + } - iterator.return(); + iterator.return(); + } } } -export const captureRejectionSymbol = Symbol.for("nodejs.rejection"); + +export { EventEmitter }; +export const once = EventEmitter.once; +export const on = EventEmitter.on; +export const captureRejectionSymbol = EventEmitter.captureRejectionSymbol; +export const errorMonitor = EventEmitter.errorMonitor; |