diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/01_core.js | 39 | ||||
-rw-r--r-- | core/lib.deno_core.d.ts | 21 | ||||
-rw-r--r-- | core/ops_builtin_v8.rs | 28 |
3 files changed, 88 insertions, 0 deletions
diff --git a/core/01_core.js b/core/01_core.js index 08f839c98..655b4219e 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -12,6 +12,7 @@ Map, Array, ArrayPrototypeFill, + ArrayPrototypePush, ArrayPrototypeMap, ErrorCaptureStackTrace, Promise, @@ -266,6 +267,43 @@ } const InterruptedPrototype = Interrupted.prototype; + const promiseHooks = { + init: [], + before: [], + after: [], + resolve: [], + hasBeenSet: false, + }; + + function setPromiseHooks(init, before, after, resolve) { + if (init) ArrayPrototypePush(promiseHooks.init, init); + if (before) ArrayPrototypePush(promiseHooks.before, before); + if (after) ArrayPrototypePush(promiseHooks.after, after); + if (resolve) ArrayPrototypePush(promiseHooks.resolve, resolve); + + if (!promiseHooks.hasBeenSet) { + promiseHooks.hasBeenSet = true; + + ops.op_set_promise_hooks((promise, parentPromise) => { + for (let i = 0; i < promiseHooks.init.length; ++i) { + promiseHooks.init[i](promise, parentPromise); + } + }, (promise) => { + for (let i = 0; i < promiseHooks.before.length; ++i) { + promiseHooks.before[i](promise); + } + }, (promise) => { + for (let i = 0; i < promiseHooks.after.length; ++i) { + promiseHooks.after[i](promise); + } + }, (promise) => { + for (let i = 0; i < promiseHooks.resolve.length; ++i) { + promiseHooks.resolve[i](promise); + } + }); + } + } + // Extra Deno.core.* exports const core = ObjectAssign(globalThis.Deno.core, { opAsync, @@ -286,6 +324,7 @@ refOp, unrefOp, setReportExceptionCallback, + setPromiseHooks, close: (rid) => ops.op_close(rid), tryClose: (rid) => ops.op_try_close(rid), read: opAsync.bind(null, "op_read"), diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts index c5662794a..7e46d0f14 100644 --- a/core/lib.deno_core.d.ts +++ b/core/lib.deno_core.d.ts @@ -164,5 +164,26 @@ declare namespace Deno { * enabled. */ const opCallTraces: Map<number, OpCallTrace>; + + /** + * Adds a callback for the given Promise event. If this function is called + * multiple times, the callbacks are called in the order they were added. + * - `init_hook` is called when a new promise is created. When a new promise + * is created as part of the chain in the case of `Promise.then` or in the + * intermediate promises created by `Promise.{race, all}`/`AsyncFunctionAwait`, + * we pass the parent promise otherwise we pass undefined. + * - `before_hook` is called at the beginning of the promise reaction. + * - `after_hook` is called at the end of the promise reaction. + * - `resolve_hook` is called at the beginning of resolve or reject function. + */ + function setPromiseHooks( + init_hook?: ( + promise: Promise<unknown>, + parentPromise?: Promise<unknown>, + ) => void, + before_hook?: (promise: Promise<unknown>) => void, + after_hook?: (promise: Promise<unknown>) => void, + resolve_hook?: (promise: Promise<unknown>) => void, + ): void; } } diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs index 3900c0641..e626c03c1 100644 --- a/core/ops_builtin_v8.rs +++ b/core/ops_builtin_v8.rs @@ -37,6 +37,7 @@ pub(crate) fn init_builtins_v8() -> Vec<OpDecl> { op_decode::decl(), op_serialize::decl(), op_deserialize::decl(), + op_set_promise_hooks::decl(), op_get_promise_details::decl(), op_get_proxy_details::decl(), op_memory_usage::decl(), @@ -575,6 +576,33 @@ fn op_get_promise_details<'a>( } } +#[op(v8)] +fn op_set_promise_hooks<'a>( + scope: &mut v8::HandleScope<'a>, + init_cb: serde_v8::Value, + before_cb: serde_v8::Value, + after_cb: serde_v8::Value, + resolve_cb: serde_v8::Value, +) -> Result<(), Error> { + let init_hook_global = to_v8_fn(scope, init_cb)?; + let before_hook_global = to_v8_fn(scope, before_cb)?; + let after_hook_global = to_v8_fn(scope, after_cb)?; + let resolve_hook_global = to_v8_fn(scope, resolve_cb)?; + let init_hook = v8::Local::new(scope, init_hook_global); + let before_hook = v8::Local::new(scope, before_hook_global); + let after_hook = v8::Local::new(scope, after_hook_global); + let resolve_hook = v8::Local::new(scope, resolve_hook_global); + + scope.get_current_context().set_promise_hooks( + init_hook, + before_hook, + after_hook, + resolve_hook, + ); + + Ok(()) +} + // Based on https://github.com/nodejs/node/blob/1e470510ff74391d7d4ec382909ea8960d2d2fbc/src/node_util.cc // Copyright Joyent, Inc. and other Node contributors. // |