diff options
author | Bert Belder <bertbelder@gmail.com> | 2023-02-10 13:06:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-10 13:06:19 +0100 |
commit | c83abb80febd6b9b4f661d13716a573e9d0cfc28 (patch) | |
tree | 6ee293f480c938bb8bea6fb4274f8589d1c11237 /core/01_core.js | |
parent | ed3a7ce2f719e64e59cfebb3d131a05a1694523b (diff) |
perf(core): speed up promise hook dispatch (#17616)
Diffstat (limited to 'core/01_core.js')
-rw-r--r-- | core/01_core.js | 97 |
1 files changed, 66 insertions, 31 deletions
diff --git a/core/01_core.js b/core/01_core.js index 6a6696bf8..bea9c4290 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -326,41 +326,76 @@ } const InterruptedPrototype = Interrupted.prototype; - const promiseHooks = { - init: [], - before: [], - after: [], - resolve: [], - hasBeenSet: false, - }; + const promiseHooks = [ + [], // init + [], // before + [], // after + [], // resolve + ]; 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); + const hooks = [init, before, after, resolve]; + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + // Skip if no callback was provided for this hook type. + if (hook == null) { + continue; + } + // Verify that the type of `hook` is a function. + if (typeof hook !== "function") { + throw new TypeError(`Expected function at position ${i}`); + } + // Add the hook to the list. + ArrayPrototypePush(promiseHooks[i], hook); + } - if (!promiseHooks.hasBeenSet) { - promiseHooks.hasBeenSet = true; + const wrappedHooks = ArrayPrototypeMap(promiseHooks, (hooks) => { + switch (hooks.length) { + case 0: + return undefined; + case 1: + return hooks[0]; + case 2: + return create2xHookWrapper(hooks[0], hooks[1]); + case 3: + return create3xHookWrapper(hooks[0], hooks[1], hooks[2]); + default: + return createHookListWrapper(hooks); + } - 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); - } - }); - } + // The following functions are used to create wrapper functions that call + // all the hooks in a list of a certain length. The reason to use a + // function that creates a wrapper is to minimize the number of objects + // captured in the closure. + function create2xHookWrapper(hook1, hook2) { + return function (promise, parent) { + hook1(promise, parent); + hook2(promise, parent); + }; + } + function create3xHookWrapper(hook1, hook2, hook3) { + return function (promise, parent) { + hook1(promise, parent); + hook2(promise, parent); + hook3(promise, parent); + }; + } + function createHookListWrapper(hooks) { + return function (promise, parent) { + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + hook(promise, parent); + } + }; + } + }); + + ops.op_set_promise_hooks( + wrappedHooks[0], + wrappedHooks[1], + wrappedHooks[2], + wrappedHooks[3], + ); } // Extra Deno.core.* exports |