博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
揭幕Vue3的proxy能做到速度加倍内存减半原因
阅读量:6000 次
发布时间:2019-06-20

本文共 3051 字,大约阅读时间需要 10 分钟。

了解过vue3更新内容的同学应该都知道,vue3的整个数据监听系统都进行了重构,由es5的Object.defineProperty改为了es6的proxy。尤大说,这个新的数据监听系统带来了初始化速度加倍同时内存占用减半的效果。本文就聊聊,为啥proxy可以做到速度加倍的同时,内存还能减半。

vue初始化过程

我们知道,vue的初始化过程,有三座大山,分别为Observer、Compiler和Watcher,当我们new Vue的时候,会调用Observer,通过Object.defineProperty来对vue对象的data,computed或者props(如果是组件的话)的所有属性进行监听,同时通过compiler解析模板指令,解析到属性后就new一个Watcher并绑定更新函数到watcher当中,Observer和Compiler就通过属性来进行关联,如此,当Observer中的setter检测到属性值改变的时候,就调用属性对应的所有watcher,调用更新函数,从而更新到属性对应的dom。 各位有兴趣的,可以看下我的。

这里面有两点需要强调下:

1、Object.defineProperty需要遍历所有的属性,这就造成了如果vue对象的data/computed/props中的数据规模庞大,那么遍历起来就会慢很多。
2、同样,如果vue对象的data/computed/props中的数据规模庞大,那么Object.defineProperty需要监听所有的属性的变化,那么占用内存就会很大。

Object.defineProperty VS Proxy

Object.definePropety的缺点

除了上面讲,在数据量庞大的情况下Object.defineProperty的两个缺点外,Object.defineProperty还有以下缺点。

1、无法监听es6的Set、WeakSet、Map、WeakMap的变化;
2、无法监听Class类型的数据;
3、属性的新加或者删除也无法监听;
4、数组元素的增加和删除也无法监听。

Proxy应运而生

针对Object.defineProperty的缺点,Proxy都能够完美得解决,它唯一的缺点就是,对IE不友好,所以vue3在检测到如果是使用IE的情况下(没错,IE11都不支持Proxy),会自动降级为Object.defineProperty的数据监听系统。所以如果是IE用户,那么就享受不到速度加倍,内存减半的体验了。

初始化对比

Object.defineProperty初始化

const data = {}for(let i = 0; i <= 100000; i++) {  data['pro' + i] = i}function defineReactive(data, property) {  let value = data[property]  Object.defineProperty(data, property, {    get() {      // console.log(`读取${property}的值为${value}`)      return value    },    set(newVal) {      // console.log(`更新${property}的值为${newVal}`)    }  })}for(let property in data) {  defineReactive(data, property)}复制代码

Proxy初始化

const data = {}for(let i = 0; i <= 100000; i++) {  data['pro' + i] = i}var proxyData = new Proxy(data, {  get(target, property, receiver) {    // console.log(`读取${property}的值为${target[property]}`)    return Reflect.get(target, property, receiver);  },  set(target, property, value, receiver) {   //  console.log(`更新${property}的值为${value}`)    return Reflect.set(target, property, value, receiver);  }})复制代码

通过devtool的performace分别对初始化和内存占用进行对比

分别实例化有1000/10000/100000/1000000个属性的对象的时间对比 分别实例化有1000/10000/100000/1000000个属性的对象的内存对比 dp=defineObjectProperty

通过对比我们知道,Proxy确实可以做到初始化速度加倍,内存占用减半的效果,为啥能做到这两点,请看开头我强调的两点,所以期待vue3的到来吧。

暴露响应式API

vue3中暴露了响应式API给用户进行数据的监控,eg:

import {observable, effect} from 'vue'const state = observable({    count: 0})effect(() => {    console.log(`count is: ${state.count}`)})// count is: 0state.count++ // count is: 1复制代码

根据这部分代码,我自己也以proxy实现了一个简单版的,有兴趣的了解下:

// cbs是Vue的一个静态属性,保存了effect的所有回调let Vue = function() {}Vue.prototype._cbs = []/*** 返回一个代理的对象,参数是需要被代理的对象**/const observable = (obj) => {  return new Proxy(obj, {    get(target, property, receiver) {      return Reflect.get(target, property, receiver)    },    set(target, property, value, receiver) {      // 取出所有effect的回调并执行      for(let cb of Vue.prototype._cbs) {        cb(value)      }      return Reflect.set(target, property, value, receiver)    }  })}/*** 只要observable的代理对象属性改变,就会执行effect的回调**/const effect = (cb) => {  Vue.prototype._cbs.push(cb)}let state = observable({  count: 0})effect((value) => {  console.log(`count is ${value}`)})state.count++复制代码

转载地址:http://cozmx.baihongyu.com/

你可能感兴趣的文章
全网最详细的Windows里Anaconda-Navigator启动后闪退的解决方案(图文详解)
查看>>
iOS开发必会的坐标系探究
查看>>
oracle易忘函数用法(5)
查看>>
MySQL root密码重置报错:mysqladmin: connect to server at 'localhost' failed的解决方案!
查看>>
hdu 2457 DNA repair
查看>>
LINUX环境变量设置
查看>>
Android定时器,推荐ScheduledThreadPoolExecutor
查看>>
百度面试总结
查看>>
php获取当月的第一天以及最后一天
查看>>
ASP.NET Core 源码学习之 Logging[1]:Introduction
查看>>
WSGI、flup、fastcgi、web.py的关系
查看>>
leetcode_question_57 Insert Interval
查看>>
日积月累:ProguardGui进行jar包代码混淆
查看>>
布里斯班初体验
查看>>
如何在Webstorm/Phpstorm中设置连接FTP,并快速进行文件比较,上传下载,同步等操作...
查看>>
将本地jar包添加到maven中
查看>>
Effective Java:对于全部对象都通用的方法
查看>>
使用Cubic Spline通过一组2D点绘制平滑曲线
查看>>
PLM_百度百科
查看>>
对语言之争的看法
查看>>