Improve rendering performance
Avoid unnecessary copies via Utils.extend in hot paths.
This commit is contained in:
committed by
Jay Linski
parent
7de4b41c34
commit
e914d6037f
@@ -20,7 +20,8 @@ export function moveHelperToHooks(instance, helperName, keepHelper) {
|
|||||||
if (instance.helpers[helperName]) {
|
if (instance.helpers[helperName]) {
|
||||||
instance.hooks[helperName] = instance.helpers[helperName];
|
instance.hooks[helperName] = instance.helpers[helperName];
|
||||||
if (!keepHelper) {
|
if (!keepHelper) {
|
||||||
delete instance.helpers[helperName];
|
// Using delete is slow
|
||||||
|
instance.helpers[helperName] = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -1,32 +1,30 @@
|
|||||||
import { createNewLookupObject } from './create-new-lookup-object';
|
import { extend } from '../utils';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
|
||||||
const loggedProperties = Object.create(null);
|
const loggedProperties = Object.create(null);
|
||||||
|
|
||||||
export function createProtoAccessControl(runtimeOptions) {
|
export function createProtoAccessControl(runtimeOptions) {
|
||||||
let defaultMethodWhiteList = Object.create(null);
|
// Create an object with "null"-prototype to avoid truthy results on
|
||||||
defaultMethodWhiteList['constructor'] = false;
|
// prototype properties.
|
||||||
defaultMethodWhiteList['__defineGetter__'] = false;
|
const propertyWhiteList = Object.create(null);
|
||||||
defaultMethodWhiteList['__defineSetter__'] = false;
|
|
||||||
defaultMethodWhiteList['__lookupGetter__'] = false;
|
|
||||||
|
|
||||||
let defaultPropertyWhiteList = Object.create(null);
|
|
||||||
// eslint-disable-next-line no-proto
|
// 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 {
|
return {
|
||||||
properties: {
|
properties: {
|
||||||
whitelist: createNewLookupObject(
|
whitelist: propertyWhiteList,
|
||||||
defaultPropertyWhiteList,
|
|
||||||
runtimeOptions.allowedProtoProperties
|
|
||||||
),
|
|
||||||
defaultValue: runtimeOptions.allowProtoPropertiesByDefault
|
defaultValue: runtimeOptions.allowProtoPropertiesByDefault
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
whitelist: createNewLookupObject(
|
whitelist: methodWhiteList,
|
||||||
defaultMethodWhiteList,
|
|
||||||
runtimeOptions.allowedProtoMethods
|
|
||||||
),
|
|
||||||
defaultValue: runtimeOptions.allowProtoMethodsByDefault
|
defaultValue: runtimeOptions.allowProtoMethodsByDefault
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-17
@@ -74,17 +74,10 @@ export function template(templateSpec, env) {
|
|||||||
}
|
}
|
||||||
partial = env.VM.resolvePartial.call(this, partial, context, options);
|
partial = env.VM.resolvePartial.call(this, partial, context, options);
|
||||||
|
|
||||||
let extendedOptions = Utils.extend({}, options, {
|
options.hooks = this.hooks;
|
||||||
hooks: this.hooks,
|
options.protoAccessControl = this.protoAccessControl;
|
||||||
protoAccessControl: this.protoAccessControl
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = env.VM.invokePartial.call(
|
let result = env.VM.invokePartial.call(this, partial, context, options);
|
||||||
this,
|
|
||||||
partial,
|
|
||||||
context,
|
|
||||||
extendedOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == null && env.compile) {
|
if (result == null && env.compile) {
|
||||||
options.partials[options.name] = env.compile(
|
options.partials[options.name] = env.compile(
|
||||||
@@ -92,7 +85,7 @@ export function template(templateSpec, env) {
|
|||||||
templateSpec.compilerOptions,
|
templateSpec.compilerOptions,
|
||||||
env
|
env
|
||||||
);
|
);
|
||||||
result = options.partials[options.name](context, extendedOptions);
|
result = options.partials[options.name](context, options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
if (options.indent) {
|
if (options.indent) {
|
||||||
@@ -247,8 +240,9 @@ export function template(templateSpec, env) {
|
|||||||
|
|
||||||
ret._setup = function(options) {
|
ret._setup = function(options) {
|
||||||
if (!options.partial) {
|
if (!options.partial) {
|
||||||
let mergedHelpers = Utils.extend({}, env.helpers, options.helpers);
|
let mergedHelpers = {};
|
||||||
wrapHelpersToPassLookupProperty(mergedHelpers, container);
|
addHelpers(mergedHelpers, env.helpers, container);
|
||||||
|
addHelpers(mergedHelpers, options.helpers, container);
|
||||||
container.helpers = mergedHelpers;
|
container.helpers = mergedHelpers;
|
||||||
|
|
||||||
if (templateSpec.usePartial) {
|
if (templateSpec.usePartial) {
|
||||||
@@ -428,9 +422,10 @@ function executeDecorators(fn, prog, container, depths, data, blockParams) {
|
|||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapHelpersToPassLookupProperty(mergedHelpers, container) {
|
function addHelpers(mergedHelpers, helpers, container) {
|
||||||
Object.keys(mergedHelpers).forEach(helperName => {
|
if (!helpers) return;
|
||||||
let helper = mergedHelpers[helperName];
|
Object.keys(helpers).forEach(helperName => {
|
||||||
|
let helper = helpers[helperName];
|
||||||
mergedHelpers[helperName] = passLookupPropertyOption(helper, container);
|
mergedHelpers[helperName] = passLookupPropertyOption(helper, container);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -438,6 +433,7 @@ function wrapHelpersToPassLookupProperty(mergedHelpers, container) {
|
|||||||
function passLookupPropertyOption(helper, container) {
|
function passLookupPropertyOption(helper, container) {
|
||||||
const lookupProperty = container.lookupProperty;
|
const lookupProperty = container.lookupProperty;
|
||||||
return wrapHelper(helper, options => {
|
return wrapHelper(helper, options => {
|
||||||
return Utils.extend({ lookupProperty }, options);
|
options.lookupProperty = lookupProperty;
|
||||||
|
return options;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user