From 93a71258ef5d52279edddc08b46b91cab6c9fa83 Mon Sep 17 00:00:00 2001 From: Mohamed Akram Date: Sun, 1 Sep 2024 20:01:43 +0400 Subject: [PATCH] Improve rendering performance Avoid unnecessary copies via Utils.extend in hot paths. --- lib/handlebars/helpers.js | 3 +- .../internal/create-new-lookup-object.js | 11 ------- lib/handlebars/internal/proto-access.js | 32 +++++++++---------- lib/handlebars/runtime.js | 20 ++++-------- 4 files changed, 24 insertions(+), 42 deletions(-) delete mode 100644 lib/handlebars/internal/create-new-lookup-object.js diff --git a/lib/handlebars/helpers.js b/lib/handlebars/helpers.js index 804796820..0a6e44024 100644 --- a/lib/handlebars/helpers.js +++ b/lib/handlebars/helpers.js @@ -20,7 +20,8 @@ export function moveHelperToHooks(instance, helperName, keepHelper) { if (instance.helpers[helperName]) { instance.hooks[helperName] = instance.helpers[helperName]; if (!keepHelper) { - delete instance.helpers[helperName]; + // Using delete is slow + instance.helpers[helperName] = undefined; } } } diff --git a/lib/handlebars/internal/create-new-lookup-object.js b/lib/handlebars/internal/create-new-lookup-object.js deleted file mode 100644 index 256f1eca1..000000000 --- a/lib/handlebars/internal/create-new-lookup-object.js +++ /dev/null @@ -1,11 +0,0 @@ -import { extend } from '../utils'; - -/** - * Create a new object with "null"-prototype to avoid truthy results on prototype properties. - * The resulting object can be used with "object[property]" to check if a property exists - * @param {...object} sources a varargs parameter of source objects that will be merged - * @returns {object} - */ -export function createNewLookupObject(...sources) { - return extend(Object.create(null), ...sources); -} diff --git a/lib/handlebars/internal/proto-access.js b/lib/handlebars/internal/proto-access.js index 424e0a714..56cf12e6e 100644 --- a/lib/handlebars/internal/proto-access.js +++ b/lib/handlebars/internal/proto-access.js @@ -1,32 +1,30 @@ -import { createNewLookupObject } from './create-new-lookup-object'; +import { extend } from '../utils'; import logger from '../logger'; const loggedProperties = Object.create(null); export function createProtoAccessControl(runtimeOptions) { - let defaultMethodWhiteList = Object.create(null); - defaultMethodWhiteList['constructor'] = false; - defaultMethodWhiteList['__defineGetter__'] = false; - defaultMethodWhiteList['__defineSetter__'] = false; - defaultMethodWhiteList['__lookupGetter__'] = false; - - let defaultPropertyWhiteList = Object.create(null); + // Create an object with "null"-prototype to avoid truthy results on + // prototype properties. + const propertyWhiteList = Object.create(null); // eslint-disable-next-line no-proto - defaultPropertyWhiteList['__proto__'] = false; + propertyWhiteList['__proto__'] = false; + extend(propertyWhiteList, runtimeOptions.allowedProtoProperties); + + const methodWhiteList = Object.create(null); + methodWhiteList['constructor'] = false; + methodWhiteList['__defineGetter__'] = false; + methodWhiteList['__defineSetter__'] = false; + methodWhiteList['__lookupGetter__'] = false; + extend(methodWhiteList, runtimeOptions.allowedProtoMethods); return { properties: { - whitelist: createNewLookupObject( - defaultPropertyWhiteList, - runtimeOptions.allowedProtoProperties - ), + whitelist: propertyWhiteList, defaultValue: runtimeOptions.allowProtoPropertiesByDefault }, methods: { - whitelist: createNewLookupObject( - defaultMethodWhiteList, - runtimeOptions.allowedProtoMethods - ), + whitelist: methodWhiteList, defaultValue: runtimeOptions.allowProtoMethodsByDefault } }; diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index b9aec1e3b..554206d8b 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -74,17 +74,10 @@ export function template(templateSpec, env) { } partial = env.VM.resolvePartial.call(this, partial, context, options); - let extendedOptions = Utils.extend({}, options, { - hooks: this.hooks, - protoAccessControl: this.protoAccessControl - }); - - let result = env.VM.invokePartial.call( - this, - partial, - context, - extendedOptions - ); + options.hooks = this.hooks; + options.protoAccessControl = this.protoAccessControl; + + let result = env.VM.invokePartial.call(this, partial, context, options); if (result == null && env.compile) { options.partials[options.name] = env.compile( @@ -92,7 +85,7 @@ export function template(templateSpec, env) { templateSpec.compilerOptions, env ); - result = options.partials[options.name](context, extendedOptions); + result = options.partials[options.name](context, options); } if (result != null) { if (options.indent) { @@ -438,6 +431,7 @@ function wrapHelpersToPassLookupProperty(mergedHelpers, container) { function passLookupPropertyOption(helper, container) { const lookupProperty = container.lookupProperty; return wrapHelper(helper, options => { - return Utils.extend({ lookupProperty }, options); + options.lookupProperty = lookupProperty; + return options; }); }