问题场景
- qiankun微前端框架的沙箱特性采用的proxy数据劫持,来完成全局变量更新,proxy是一个元编程的工具,可以自定义对象特性触发副作用,因此对性能产生一定的影响,因此在微前端使用大数据量渲染下会产生一定的延迟。
引发思考
- vue3也是使用proxy处理响应式数据变化,他对性能做了哪些优化?
vue3数据劫持的优化
- 缓存响应式对象。vue3会将响应式对象缓存起来,避免重复创建proxy对象,从而提供性能
- 懒执行响应式数据。vue3会将响应式数据的访问和修改操作延迟到实际需要时候才执行,避免不必要的性能开销
- 批量更新响应式数据。vue3会将多个响应式数据更新操作合并成一个批处理,减少更新次数提高性能
以上优化思路适用一切性能优化
探讨方案一
缓存响应式对象
纵观qiankun2做的缓存优化:
const windowProxy = new Proxy(window, traps);
with(windowProxy) {
// 应用代码,通过 with 确保所有的全局变量的操作实际都是在操作 qiankun 提供的代理对象
+ // 提前将一些全局变量通过 赋值/取值 从 proxy 里缓存下来
- var undefined = windowProxy.undefined; var Array = windowProxy.Array; var Promise = windowProxy.Promise;
+ const undefined = windowProxy.undefined; const Array = windowProxy.Array; const Promise = windowProxy.Promise;
${appCode}
}
疑问
使用with语句扩展作用域链,直接访问对象属性并缓存,但此处把var定义改为const定义,是为什么?
- 首先按照常识,既然使用proxy了,那肯定也支持let、const块级作用域,按习惯直接上手const
- 其次,如果定义var应该也没问题,那为什么要删掉改成const
解决思路
- 首先,
with语句是 JavaScript 中的一个语法特性,用于扩展语句的作用域链,允许在语句块中直接访问指定对象的属性,而无需重复引用对象本身。 - 因此它本身是会修改作用域链顺序的,它拥有自己的作用域,所以用var定义会修改作用域的一个范围,出现意外
最后
with 语句的问题
尽管 with 语句可以简化代码,但它存在以下问题:
(1)性能问题
with语句会改变作用域链,导致 JavaScript 引擎无法在编译时优化变量查找,从而降低性能。
(2)代码可读性问题
with语句使得代码的可读性和可维护性变差,因为很难确定变量是来自with对象还是外部作用域。
(3)潜在的错误
- 如果
with对象中没有某个属性,JavaScript 会继续在外部作用域中查找,可能导致意外的行为。
(4)严格模式禁用
- 在严格模式(
strict mode)下,with语句是被禁用的,使用会报错。
替代方案:
使用解构赋值、临时变量或函数参数等方式替代 with 语句,以提高代码的可读性和性能。