️ optimize sandbox performance (#978)

This commit is contained in:
Kuitos 2020-10-12 15:20:33 +08:00 committed by GitHub
parent b7d5adeb2a
commit 1446c6b212
3 changed files with 25 additions and 8 deletions

View File

@ -27,7 +27,12 @@ export function getTargetValue(target: any, value: any): any {
const boundValue = value.bind(target); const boundValue = value.bind(target);
// some callable function has custom fields, we need to copy the enumerable props to boundValue. such as moment function. // some callable function has custom fields, we need to copy the enumerable props to boundValue. such as moment function.
Object.keys(value).forEach(key => (boundValue[key] = value[key])); // use for..in rather than Object.keys.forEach for performance reason
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const key in value) {
boundValue[key] = value[key];
}
// copy prototype, for performance reason, we use in operator to check rather than hasOwnProperty // copy prototype, for performance reason, we use in operator to check rather than hasOwnProperty
if ('prototype' in value) boundValue.prototype = value.prototype; if ('prototype' in value) boundValue.prototype = value.prototype;
Object.defineProperty(value, boundValueSymbol, { enumerable: false, value: boundValue }); Object.defineProperty(value, boundValueSymbol, { enumerable: false, value: boundValue });
@ -37,7 +42,7 @@ export function getTargetValue(target: any, value: any): any {
return value; return value;
} }
const getterInvocationResultMap = new Map<CallableFunction, any>(); const getterInvocationResultMap = new WeakMap<CallableFunction, any>();
export function getProxyPropertyValue(getter: CallableFunction) { export function getProxyPropertyValue(getter: CallableFunction) {
const getterResult = getterInvocationResultMap.get(getter); const getterResult = getterInvocationResultMap.get(getter);

View File

@ -33,7 +33,7 @@ const SCRIPT_TAG_NAME = 'SCRIPT';
const LINK_TAG_NAME = 'LINK'; const LINK_TAG_NAME = 'LINK';
const STYLE_TAG_NAME = 'STYLE'; const STYLE_TAG_NAME = 'STYLE';
const proxyContainerInfoMapper = new Map<WindowProxy, Record<string, any>>(); const proxyContainerInfoMapper = new WeakMap<WindowProxy, Record<string, any>>();
function isHijackingTag(tagName?: string) { function isHijackingTag(tagName?: string) {
return ( return (

View File

@ -22,16 +22,22 @@ export function nextTick(cb: () => void): void {
Promise.resolve().then(cb); Promise.resolve().then(cb);
} }
export function isConstructable(fn: () => void | FunctionConstructor) { const constructableMap = new WeakMap<Function, boolean>();
export function isConstructable(fn: () => any | FunctionConstructor) {
if (constructableMap.has(fn)) {
return constructableMap.get(fn);
}
const constructableFunctionRegex = /^function\b\s[A-Z].*/; const constructableFunctionRegex = /^function\b\s[A-Z].*/;
const classRegex = /^class\b/; const classRegex = /^class\b/;
// 有 prototype 并且 prototype 上有定义一系列非 constructor 属性,则可以认为是一个构造函数 // 有 prototype 并且 prototype 上有定义一系列非 constructor 属性,则可以认为是一个构造函数
return ( const constructable =
(fn.prototype && fn.prototype.constructor === fn && Object.getOwnPropertyNames(fn.prototype).length > 1) || (fn.prototype && fn.prototype.constructor === fn && Object.getOwnPropertyNames(fn.prototype).length > 1) ||
constructableFunctionRegex.test(fn.toString()) || constructableFunctionRegex.test(fn.toString()) ||
classRegex.test(fn.toString()) classRegex.test(fn.toString());
); constructableMap.set(fn, constructable);
return constructable;
} }
/** /**
@ -45,12 +51,18 @@ export const isCallable = naughtySafari
? (fn: any) => typeof fn === 'function' && typeof fn !== 'undefined' ? (fn: any) => typeof fn === 'function' && typeof fn !== 'undefined'
: (fn: any) => typeof fn === 'function'; : (fn: any) => typeof fn === 'function';
const boundedMap = new WeakMap<CallableFunction, boolean>();
export function isBoundedFunction(fn: CallableFunction) { export function isBoundedFunction(fn: CallableFunction) {
if (boundedMap.has(fn)) {
return boundedMap.get(fn);
}
/* /*
indexOf is faster than startsWith indexOf is faster than startsWith
see https://jsperf.com/string-startswith/72 see https://jsperf.com/string-startswith/72
*/ */
return fn.name.indexOf('bound ') === 0 && !fn.hasOwnProperty('prototype'); const bounded = fn.name.indexOf('bound ') === 0 && !fn.hasOwnProperty('prototype');
boundedMap.set(fn, bounded);
return bounded;
} }
/** /**