Vue3 对Proxy 、defineProperty的选择

Vue3 对Proxy 、defineProperty的选择

1. Proxy 的性能,可能比 defineProperty 更差

我们在大数据量循环的过程中,分别用 Object.definePropertyProxy 劫持的数据,执行一次 gettersetter。然后利用 performance.now 记录执行时间。

先看 defineProperty 的案例。

首先定义一个简单对象

js 复制代码
// 在循环中,我们会执行计算操作
var target = {
  total: 0
}

然后另外定义一个普通变量用于存储劫持过程中访问和设置的值。

然后用 Object.defineProperty 劫持 target。

js 复制代码
Object.defineProperty(target, 'count', {
  get: function () {
    return b;
  },
  set: function (value) {
    b = value;
  },
});

然后循环 1000000 次,并打印执行时间

js 复制代码
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
  total += target.count;
  target.count = index;
}
console.log('defineProperty', performance.now() - now)

接下来看使用 Proxy 的案例。

也是首先定义一个普通对象

js 复制代码
var target = {
  count: 0
}

然后使用 Proxy 代理。

js 复制代码
let proxy = new Proxy(target, {
  get: (target, prop, receiver) => {
    return Reflect.get(target, prop, receiver)
  },
  set(target, prop, value) {
    return Reflect.set(target, prop, value)
  }
});

然后循环访问 getter 和 setter

js 复制代码
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
  total += proxy.count;
  proxy.count = index;
  proxy.count
}
console.log('Proxy', performance.now() - now)

完整代码如下

js 复制代码
<script>
var end = 1000000
var b = 0;
var target = {
  count: 0
}

Object.defineProperty(target, 'count', {
  get: function () {
    return b;
  },
  set: function (value) {
    b = value;
  },
});
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
  total += target.count;
  target.count = index;
}
console.log('defineProperty', performance.now() - now)
</script>
js 复制代码
<script>
var end = 1000000
var target = {
  count: 0
}

let proxy = new Proxy(target, {
  get: (target, prop, receiver) => {
    return Reflect.get(target, prop, receiver)
  },
  set(target, prop, value) {
    return Reflect.set(target, prop, value)
  }
});

var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
  total += proxy.count;
  proxy.count = index;
}
console.log('Proxy', performance.now() - now)
</script>

在 chrome 中执行结果为:

执行时间上,Proxy 用时更久

在 safari 中执行结果为:

在 safari 浏览器中,Proxy 的性能严重低于 defineProperty.

firefox 的执行结果差异最大。

然后尝试让 Proxy 代理的对象增加层级,然后进行 set 操作

注意,这里只是简单的增加对象复杂度,并不代表更深层级的属性也能被代理。

js 复制代码
var target = {
  count: 0,
  b: {
    c: 0
  }
}
js 复制代码
for (let index = 0; index < end; index++) {
  total += proxy.count;
  proxy.count = index;
  proxy.b.c = target.count
}

验证结果发现,当层级变深,执行消耗的时间越长。下图是 chrome 的执行结果。

结论

在常用的几种浏览器中,Proxy 的性能都弱于 defineProperty,在 safari,firefox 中,defineProperty 的性能大幅度领先。针对 Proxy 的性能,chrome 优化做得最好。但依然小幅度弱于 defineProperty。

2. Proxy相对于defineProperty的优势

  • Proxy可以直接监听对象而非属性

  • Proxy可以直接监听数组的变化

    • 当我们对数组进行操作(push、shift、splice等)时,会触发对应的方法名称和length 的变化,我们可以借此进行操作,以上Object.defineProperty无法生效。
  • Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。

  • Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改。

  • Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。

3. Vue3 对Proxy 、defineProperty的选择

  • 根据以上知识,可知Proxy 的功能更强大,但需要更多的开销;
  • 所以,Vue3 里用于定义复杂数据类型的Reactive选择Proxy,用于定义简单数据类型的ref使用defineProperty劫持getter/setter
相关推荐
文艺理科生5 分钟前
Google A2UI 解读:当 AI 不再只是陪聊,而是开始画界面
前端·vue.js·人工智能
json{shen:"jing"}24 分钟前
08_组件基础
前端·javascript·vue.js
hxjhnct2 小时前
React 为什么不采用(VUE)绑定数据?
javascript·vue.js·react.js
Knight_AL2 小时前
Vue + Spring Boot 项目添加 /wvp 前缀的完整链路解析(从浏览器到静态资源)
前端·vue.js·spring boot
技术钱2 小时前
vue3 + element plus实现表头拖拽数组进行汇总
前端·javascript·vue.js
chenhdowue2 小时前
vue 如何实现 vxe-table 的按键操作回车键的上下移动修改为 Tab 键的左右切换
vue.js·vxe-table·vxe-ui
柒@宝儿姐2 小时前
vue3中使用element-plus的el-scrollbar实现滚动触底加载更多
前端·javascript·vue.js
蜗牛攻城狮2 小时前
深入理解 Vue.js 中的「运行时」与「编译时」:从模板到虚拟 DOM 的全过程
前端·javascript·vue.js
Knight_AL2 小时前
Vue 项目部署在子目录下:hash vs history 的真实区别
前端·vue.js·哈希算法
zhaocarbon2 小时前
VUE 4向云台 8向云台UI
css·vue.js·ui