mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
fix(ext/node): implement EventEmitterAsyncResource (#22994)
Fixes #22729
This commit is contained in:
parent
5b2f689f08
commit
724cdcec7b
3 changed files with 127 additions and 1 deletions
|
@ -32,14 +32,17 @@ import {
|
||||||
AbortError,
|
AbortError,
|
||||||
// kEnhanceStackBeforeInspector,
|
// kEnhanceStackBeforeInspector,
|
||||||
ERR_INVALID_ARG_TYPE,
|
ERR_INVALID_ARG_TYPE,
|
||||||
|
ERR_INVALID_THIS,
|
||||||
ERR_OUT_OF_RANGE,
|
ERR_OUT_OF_RANGE,
|
||||||
ERR_UNHANDLED_ERROR,
|
ERR_UNHANDLED_ERROR,
|
||||||
} from "ext:deno_node/internal/errors.ts";
|
} from "ext:deno_node/internal/errors.ts";
|
||||||
|
|
||||||
|
import { AsyncResource } from "node:async_hooks";
|
||||||
import {
|
import {
|
||||||
validateAbortSignal,
|
validateAbortSignal,
|
||||||
validateBoolean,
|
validateBoolean,
|
||||||
validateFunction,
|
validateFunction,
|
||||||
|
validateString,
|
||||||
} from "ext:deno_node/internal/validators.mjs";
|
} from "ext:deno_node/internal/validators.mjs";
|
||||||
import { spliceOne } from "ext:deno_node/_utils.ts";
|
import { spliceOne } from "ext:deno_node/_utils.ts";
|
||||||
import { nextTick } from "ext:deno_node/_process/process.ts";
|
import { nextTick } from "ext:deno_node/_process/process.ts";
|
||||||
|
@ -1035,3 +1038,116 @@ export function on(emitter, event, options) {
|
||||||
iterator.return();
|
iterator.return();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const kAsyncResource = Symbol("kAsyncResource");
|
||||||
|
const kEventEmitter = Symbol("kEventEmitter");
|
||||||
|
|
||||||
|
class EventEmitterReferencingAsyncResource extends AsyncResource {
|
||||||
|
/**
|
||||||
|
* @param {EventEmitter} ee
|
||||||
|
* @param {string} [type]
|
||||||
|
* @param {{
|
||||||
|
* triggerAsyncId?: number,
|
||||||
|
* requireManualDestroy?: boolean,
|
||||||
|
* }} [options]
|
||||||
|
*/
|
||||||
|
constructor(ee, type, options) {
|
||||||
|
super(type, options);
|
||||||
|
this[kEventEmitter] = ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {EventEmitter}
|
||||||
|
*/
|
||||||
|
get eventEmitter() {
|
||||||
|
if (this[kEventEmitter] === undefined) {
|
||||||
|
throw new ERR_INVALID_THIS("EventEmitterReferencingAsyncResource");
|
||||||
|
}
|
||||||
|
return this[kEventEmitter];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EventEmitterAsyncResource extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* name?: string,
|
||||||
|
* triggerAsyncId?: number,
|
||||||
|
* requireManualDestroy?: boolean,
|
||||||
|
* }} [options]
|
||||||
|
*/
|
||||||
|
constructor(options = undefined) {
|
||||||
|
let name;
|
||||||
|
if (typeof options === "string") {
|
||||||
|
name = options;
|
||||||
|
options = undefined;
|
||||||
|
} else {
|
||||||
|
if (new.target === EventEmitterAsyncResource) {
|
||||||
|
validateString(options?.name, "options.name");
|
||||||
|
}
|
||||||
|
name = options?.name || new.target.name;
|
||||||
|
}
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
this[kAsyncResource] = new EventEmitterReferencingAsyncResource(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {symbol,string} event
|
||||||
|
* @param {...any} args
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
emit(event, ...args) {
|
||||||
|
if (this[kAsyncResource] === undefined) {
|
||||||
|
throw new ERR_INVALID_THIS("EventEmitterAsyncResource");
|
||||||
|
}
|
||||||
|
const { asyncResource } = this;
|
||||||
|
args.unshift(super.emit, this, event);
|
||||||
|
return asyncResource.runInAsyncScope.apply(asyncResource, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
emitDestroy() {
|
||||||
|
if (this[kAsyncResource] === undefined) {
|
||||||
|
throw new ERR_INVALID_THIS("EventEmitterAsyncResource");
|
||||||
|
}
|
||||||
|
this.asyncResource.emitDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get asyncId() {
|
||||||
|
if (this[kAsyncResource] === undefined) {
|
||||||
|
throw new ERR_INVALID_THIS("EventEmitterAsyncResource");
|
||||||
|
}
|
||||||
|
return this.asyncResource.asyncId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get triggerAsyncId() {
|
||||||
|
if (this[kAsyncResource] === undefined) {
|
||||||
|
throw new ERR_INVALID_THIS("EventEmitterAsyncResource");
|
||||||
|
}
|
||||||
|
return this.asyncResource.triggerAsyncId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {EventEmitterReferencingAsyncResource}
|
||||||
|
*/
|
||||||
|
get asyncResource() {
|
||||||
|
if (this[kAsyncResource] === undefined) {
|
||||||
|
throw new ERR_INVALID_THIS("EventEmitterAsyncResource");
|
||||||
|
}
|
||||||
|
return this[kAsyncResource];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource;
|
||||||
|
|
|
@ -6,6 +6,7 @@ export {
|
||||||
defaultMaxListeners,
|
defaultMaxListeners,
|
||||||
errorMonitor,
|
errorMonitor,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
|
EventEmitterAsyncResource,
|
||||||
getEventListeners,
|
getEventListeners,
|
||||||
listenerCount,
|
listenerCount,
|
||||||
on,
|
on,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
import { EventEmitter } from "node:events";
|
import events, { EventEmitter } from "node:events";
|
||||||
|
|
||||||
EventEmitter.captureRejections = true;
|
EventEmitter.captureRejections = true;
|
||||||
|
|
||||||
|
@ -25,3 +25,12 @@ Deno.test("regression #20441", async () => {
|
||||||
ee.emit("foo");
|
ee.emit("foo");
|
||||||
await promise;
|
await promise;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test("eventemitter async resource", () => {
|
||||||
|
// @ts-ignore: @types/node is outdated
|
||||||
|
class Foo extends events.EventEmitterAsyncResource {}
|
||||||
|
|
||||||
|
const foo = new Foo();
|
||||||
|
// @ts-ignore: @types/node is outdated
|
||||||
|
foo.emit("bar");
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue