icestark
icestark copied to clipboard
Feat/sandbox optimization
在使用icestarkk开启沙箱接入子应用的时,我们发现在遇到执行的js代码需要频繁访问沙箱时,会遇到明显的性能问题和卡顿。 针对此问题,笔者想到了一种解决方法: 在使用时将常用的变量进行缓存,这样相关的变量就只会访问一次沙箱,之后代码执行时就不再需要再多次重复访问沙箱。
在后续学习中发现另一个微前端框架qiankun也在沙箱中默认开启使用类似的缓存方法来对沙箱性能进行优化,pr中的缓存的变量以及写法参考了qiankun。
下面是一个将icestark的sandbox核心代码简化后的例子:
// 简易沙箱
const sandbox = new Proxy(window, {
get(target, prop, receiver) {
if (prop === Symbol.unscopables) {
return undefined;
}
console.log('访问了沙箱', prop)
return target[prop]
}
});
const start = performance.now();
const testScript = `
// 执行的js代码,会频繁访问沙箱
for (let i = 1; i <= 1000; i++) {
const li = document.createElement('li');
Math.abs(i)
Math.random()
new Array(3)
let arr = new Array(3)
Array.isArray(arr)
}
`;
const execScript = `with (sandbox) {;${testScript}\n}`;
const code = new Function('sandbox', execScript).bind(sandbox);
code(sandbox);
console.log('Time taken: ', performance.now() - start);
未进行缓存时候,以上代码中的Math等变量每执行一次都会访问沙箱造成不必要的性能开销,以上代码实际执行下来的时间大约在70ms。 如果简易沙箱开启缓存后,代码实际执行时间在0.8ms,性能差距非常明显。(图片在最后) 下面是简易沙箱开启缓存的示例代码:
const testScript = `
// 下面是添加的缓存的代码
const Math = sandbox.Math
const Array = sandbox.Array
const undefined = sandbox.undefined
const Object = sandbox.Object
const Promise = sandbox.Promise
const setTimeout = sandbox.setTimeout
const console = sandbox.console
const document = sandbox.document
// 执行的js代码,会频繁访问沙箱
for (let i = 1; i <= 1000; i++) {
const li = document.createElement('li');
Math.abs(i)
Math.random()
new Array(3)
let arr = new Array(3)
Array.isArray(arr)
}
`;
在icestark沙箱中加上缓存后实际测试的效果: 测试示例代码未进行缓存前平均执行时间在54ms左右,开启缓存后的平均执行时间在19ms作用,速度提升了三倍左右 测试代码:
describe('sandbox: performance', () => {
const testScript = `
for (let i = 1; i <= 1000; i++) {
const li = document.createElement('li');
Math.abs(i);
Math.random();
new Array(3);
let arr = new Array(3);
Array.isArray(arr);
Array.isArray([1,2,i]);
new Date()
requestAnimationFrame((i) => animate(i));
JSON.stringify(i)
new Map()
const object1 = {
a: "somestring",
b: i,
c: false,
};
Object.values(object1)
}
`;
test('execution time', () => {
// 测试沙盒执行时间
const sandbox = new Sandbox();
const sandboxStart = performance.now();
sandbox.execScriptInSandbox(testScript);
const sandboxTime = performance.now() - sandboxStart;
console.log(`Sandbox execution time: ${sandboxTime.toFixed(2)}ms`);
expect(sandboxTime).toBeGreaterThan(0);
// 清理沙盒
sandbox.clear();
});
});
简易沙箱示例执行结果图片:
补充:已通过代码中全部sandbox测试用例