From cde3928a10627510ae0aee7728e5498a95235482 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Thu, 6 Jun 2019 09:18:41 +0200 Subject: [PATCH] process: improve queueMicrotask performance Optimize the hot code paths of queueMicrotask by not creating unnecessary objects, not looking up properties on frozen primordials, etc. PR-URL: https://github.com/nodejs/node/pull/28093 Reviewed-By: Ruben Bridgewater Reviewed-By: Gus Caplan Reviewed-By: Matteo Collina --- lib/async_hooks.js | 26 +++++++++++++++----------- lib/internal/process/task_queues.js | 8 +++----- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/async_hooks.js b/lib/async_hooks.js index 3a12a241ea5d5f..0c177055364e41 100644 --- a/lib/async_hooks.js +++ b/lib/async_hooks.js @@ -134,15 +134,16 @@ class AsyncResource { constructor(type, opts = {}) { validateString(type, 'type'); - if (typeof opts === 'number') { - opts = { triggerAsyncId: opts, requireManualDestroy: false }; - } else if (opts.triggerAsyncId === undefined) { - opts.triggerAsyncId = getDefaultTriggerAsyncId(); + let triggerAsyncId = opts; + let requireManualDestroy = false; + if (typeof opts !== 'number') { + triggerAsyncId = opts.triggerAsyncId === undefined ? + getDefaultTriggerAsyncId() : opts.triggerAsyncId; + requireManualDestroy = !!opts.requireManualDestroy; } // Unlike emitInitScript, AsyncResource doesn't supports null as the // triggerAsyncId. - const triggerAsyncId = opts.triggerAsyncId; if (!Number.isSafeInteger(triggerAsyncId) || triggerAsyncId < -1) { throw new ERR_INVALID_ASYNC_ID('triggerAsyncId', triggerAsyncId); } @@ -151,15 +152,14 @@ class AsyncResource { this[async_id_symbol] = asyncId; this[trigger_async_id_symbol] = triggerAsyncId; - // This prop name (destroyed) has to be synchronized with C++ - const destroyed = { destroyed: false }; - this[destroyedSymbol] = destroyed; - if (initHooksExist()) { emitInit(asyncId, type, triggerAsyncId, this); } - if (!opts.requireManualDestroy) { + if (!requireManualDestroy) { + // This prop name (destroyed) has to be synchronized with C++ + const destroyed = { destroyed: false }; + this[destroyedSymbol] = destroyed; registerDestroyHook(this, asyncId, destroyed); } } @@ -168,6 +168,8 @@ class AsyncResource { const asyncId = this[async_id_symbol]; emitBefore(asyncId, this[trigger_async_id_symbol]); try { + if (thisArg === undefined) + return fn(...args); return Reflect.apply(fn, thisArg, args); } finally { emitAfter(asyncId); @@ -175,7 +177,9 @@ class AsyncResource { } emitDestroy() { - this[destroyedSymbol].destroyed = true; + if (this[destroyedSymbol] !== undefined) { + this[destroyedSymbol].destroyed = true; + } emitDestroy(this[async_id_symbol]); return this; } diff --git a/lib/internal/process/task_queues.js b/lib/internal/process/task_queues.js index 1f203c86ed522f..34e925aaf57d08 100644 --- a/lib/internal/process/task_queues.js +++ b/lib/internal/process/task_queues.js @@ -128,15 +128,13 @@ function nextTick(callback) { } let AsyncResource; +const defaultMicrotaskResourceOpts = { requireManualDestroy: true }; function createMicrotaskResource() { // Lazy load the async_hooks module - if (!AsyncResource) { + if (AsyncResource === undefined) { AsyncResource = require('async_hooks').AsyncResource; } - return new AsyncResource('Microtask', { - triggerAsyncId: getDefaultTriggerAsyncId(), - requireManualDestroy: true, - }); + return new AsyncResource('Microtask', defaultMicrotaskResourceOpts); } function runMicrotask() {