1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00
denoland-deno/ext/node/polyfills/async_hooks.ts
snek f7556d8962
fix: reland async context (#25140)
This reverts commit 71ca61e189.

Now uses a shared implementation from deno_core.
2024-08-29 02:25:38 +00:00

182 lines
3.9 KiB
TypeScript

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
import { core, primordials } from "ext:core/mod.js";
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
import { newAsyncId } from "ext:deno_node/internal/async_hooks.ts";
const {
ObjectDefineProperties,
ReflectApply,
FunctionPrototypeBind,
ArrayPrototypeUnshift,
ObjectFreeze,
} = primordials;
const {
AsyncVariable,
getAsyncContext,
setAsyncContext,
} = core;
export class AsyncResource {
type: string;
#snapshot: unknown;
#asyncId: number;
constructor(type: string) {
this.type = type;
this.#snapshot = getAsyncContext();
this.#asyncId = newAsyncId();
}
asyncId() {
return this.#asyncId;
}
runInAsyncScope(
fn: (...args: unknown[]) => unknown,
thisArg: unknown,
...args: unknown[]
) {
const previousContext = getAsyncContext();
try {
setAsyncContext(this.#snapshot);
return ReflectApply(fn, thisArg, args);
} finally {
setAsyncContext(previousContext);
}
}
emitDestroy() {}
bind(fn: (...args: unknown[]) => unknown, thisArg) {
validateFunction(fn, "fn");
let bound;
if (thisArg === undefined) {
// deno-lint-ignore no-this-alias
const resource = this;
bound = function (...args) {
ArrayPrototypeUnshift(args, fn, this);
return ReflectApply(resource.runInAsyncScope, resource, args);
};
} else {
bound = FunctionPrototypeBind(this.runInAsyncScope, this, fn, thisArg);
}
ObjectDefineProperties(bound, {
"length": {
__proto__: null,
configurable: true,
enumerable: false,
value: fn.length,
writable: false,
},
});
return bound;
}
static bind(
fn: (...args: unknown[]) => unknown,
type?: string,
thisArg?: AsyncResource,
) {
type = type || fn.name || "bound-anonymous-fn";
return (new AsyncResource(type)).bind(fn, thisArg);
}
}
export class AsyncLocalStorage {
#variable = new AsyncVariable();
enabled = false;
// deno-lint-ignore no-explicit-any
run(store: any, callback: any, ...args: any[]): any {
this.enabled = true;
const previous = this.#variable.enter(store);
try {
return ReflectApply(callback, null, args);
} finally {
setAsyncContext(previous);
}
}
// deno-lint-ignore no-explicit-any
exit(callback: (...args: unknown[]) => any, ...args: any[]): any {
if (!this.enabled) {
return ReflectApply(callback, null, args);
}
this.enabled = false;
try {
return ReflectApply(callback, null, args);
} finally {
this.enabled = true;
}
}
// deno-lint-ignore no-explicit-any
getStore(): any {
if (!this.enabled) {
return undefined;
}
return this.#variable.get();
}
enterWith(store: unknown) {
this.enabled = true;
this.#variable.enter(store);
}
disable() {
this.enabled = false;
}
static bind(fn: (...args: unknown[]) => unknown) {
return AsyncResource.bind(fn);
}
static snapshot() {
return AsyncLocalStorage.bind((
cb: (...args: unknown[]) => unknown,
...args: unknown[]
) => ReflectApply(cb, null, args));
}
}
export function executionAsyncId() {
return 0;
}
export function triggerAsyncId() {
return 0;
}
export function executionAsyncResource() {
return {};
}
export const asyncWrapProviders = ObjectFreeze({ __proto__: null });
class AsyncHook {
enable() {
}
disable() {
}
}
export function createHook() {
return new AsyncHook();
}
export default {
AsyncLocalStorage,
createHook,
executionAsyncId,
triggerAsyncId,
executionAsyncResource,
asyncWrapProviders,
AsyncResource,
};