️ 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);
// 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
if ('prototype' in value) boundValue.prototype = value.prototype;
Object.defineProperty(value, boundValueSymbol, { enumerable: false, value: boundValue });
@ -37,7 +42,7 @@ export function getTargetValue(target: any, value: any): any {
return value;
}
const getterInvocationResultMap = new Map<CallableFunction, any>();
const getterInvocationResultMap = new WeakMap<CallableFunction, any>();
export function getProxyPropertyValue(getter: CallableFunction) {
const getterResult = getterInvocationResultMap.get(getter);

View File

@ -33,7 +33,7 @@ const SCRIPT_TAG_NAME = 'SCRIPT';
const LINK_TAG_NAME = 'LINK';
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) {
return (

View File

@ -22,16 +22,22 @@ export function nextTick(cb: () => void): void {
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 classRegex = /^class\b/;
// 有 prototype 并且 prototype 上有定义一系列非 constructor 属性,则可以认为是一个构造函数
return (
const constructable =
(fn.prototype && fn.prototype.constructor === fn && Object.getOwnPropertyNames(fn.prototype).length > 1) ||
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';
const boundedMap = new WeakMap<CallableFunction, boolean>();
export function isBoundedFunction(fn: CallableFunction) {
if (boundedMap.has(fn)) {
return boundedMap.get(fn);
}
/*
indexOf is faster than startsWith
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;
}
/**