diff --git a/benchmark/util/deprecate.js b/benchmark/util/deprecate.js new file mode 100644 index 00000000000000..a94a7606321003 --- /dev/null +++ b/benchmark/util/deprecate.js @@ -0,0 +1,36 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const bench = common.createBenchmark(main, { + n: [1e5], + modifyPrototype: [1, 0], + emitWarningSync: [1, 0], +}, { + flags: ['--expose-internals'], +}); + +function simpleFunction(x) { + return x * 2 + (new Array(1000)).fill(0).map((_, i) => i).reduce((a, b) => a + b, 0); +} + +function main({ n, modifyPrototype, emitWarningSync }) { + const { deprecate } = require('internal/util'); + + const fn = deprecate( + simpleFunction, + 'This function is deprecated', + 'DEP0000', + emitWarningSync, + !!modifyPrototype, + ); + + let sum = 0; + bench.start(); + for (let i = 0; i < n; ++i) { + sum += fn(i); + } + bench.end(n); + assert.ok(sum); +} diff --git a/lib/internal/util.js b/lib/internal/util.js index 180ca49b3207eb..f60a9b00b0fe5e 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -169,7 +169,7 @@ function pendingDeprecate(fn, msg, code) { // Mark that a method should not be used. // Returns a modified function which warns once by default. // If --no-deprecation is set, then it is a no-op. -function deprecate(fn, msg, code, useEmitSync) { +function deprecate(fn, msg, code, useEmitSync, modifyPrototype = true) { // Lazy-load to avoid a circular dependency. if (validateString === undefined) ({ validateString } = require('internal/validators')); @@ -192,19 +192,23 @@ function deprecate(fn, msg, code, useEmitSync) { return ReflectApply(fn, this, args); } - // The wrapper will keep the same prototype as fn to maintain prototype chain - ObjectSetPrototypeOf(deprecated, fn); - if (fn.prototype) { - // Setting this (rather than using Object.setPrototype, as above) ensures - // that calling the unwrapped constructor gives an instanceof the wrapped - // constructor. - deprecated.prototype = fn.prototype; - } + if (modifyPrototype) { + // The wrapper will keep the same prototype as fn to maintain prototype chain + // Modifying the prototype does alter the object chains, and as observed in + // most cases, it slows the code. + ObjectSetPrototypeOf(deprecated, fn); + if (fn.prototype) { + // Setting this (rather than using Object.setPrototype, as above) ensures + // that calling the unwrapped constructor gives an instanceof the wrapped + // constructor. + deprecated.prototype = fn.prototype; + } - ObjectDefineProperty(deprecated, 'length', { - __proto__: null, - ...ObjectGetOwnPropertyDescriptor(fn, 'length'), - }); + ObjectDefineProperty(deprecated, 'length', { + __proto__: null, + ...ObjectGetOwnPropertyDescriptor(fn, 'length'), + }); + } return deprecated; }