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
相关推荐
q***385111 小时前
SpringBoot + vue 管理系统
vue.js·spring boot·后端
喵个咪11 小时前
go-kratos-admin 快速上手指南:从环境搭建到启动服务(Windows/macOS/Linux 通用)
vue.js·go
用户8417948145611 小时前
vxe-gantt table 甘特图如何设置任务视图每一行的背景色
vue.js
小章鱼学前端12 小时前
2025 年最新 Fabric.js 实战:一个完整可上线的图片选区标注组件(含全部源码).
前端·vue.js
涔溪12 小时前
实现将 Vue3 项目作为子应用,通过无界(Wujie)微前端框架接入到 Vue2 主应用中(Vue2 为主应用,Vue3 为子应用)
vue.js·前端框架·wujie
源码技术栈15 小时前
什么是云门诊系统、云诊所系统?
java·vue.js·spring boot·源码·门诊·云门诊
lcc18715 小时前
Vue3 ref函数和reactive函数
前端·vue.js
艾小码15 小时前
还在为组件通信头疼?defineExpose让你彻底告别传值烦恼
前端·javascript·vue.js
带只拖鞋去流浪15 小时前
迎接2026,重新认识Vue CLI (v5.x)
前端·vue.js·webpack
Coder-coco15 小时前
游戏助手|游戏攻略|基于SprinBoot+vue的游戏攻略系统小程序(源码+数据库+文档)
java·vue.js·spring boot·游戏·小程序·论文·游戏助手