美文网首页
回顾Vue2,面向Vue3

回顾Vue2,面向Vue3

作者: hellomyshadow | 来源:发表于2020-07-19 16:07 被阅读0次

Vue2的历史问题

Object.defineProperty() 是可以监听数组的,key是角标,value是元素值。
但对数组插入、删除、排序操作时,数据元素的位置会发生移动,造成每个元素的getter、setter频繁调用,严重影响性能!所以,Vue2 放弃使用监听数组!

function defineReactive(data, key, value) {
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function defineGet() {
            return value
        },
        set: function defineSet(newVal) {
            value = newVal
        }
    })
}
function observe(data) {
    Object.keys(data).forEach(key => {
        defineReactive(data, key, data[key])
    })
}

var arr = ['a', 'b', 'c']
observe(arr)

Object.defineProperty() 的真正问题是:不能对初始化时没有设置的键值做监听!

var arr = [1, 2, 3]
observe(arr)
arr.push(4)  // 无法监听角标为 3,元素值为4 的数组元素

var obj = { name: 'Jscript' }
observe(obj)
obj.age = 18  //无法监听 age 属性

这也是为什么会有Vue2要重写数组的方法,并提供 Vue.setAPI
另外,Object.defineProperty() 需要一开始就初始化递归遍历,循环监听,这也是性能瓶颈之一。

也正是因为这些历史遗留问题,才会有Vue3

Vue3 Proxy

Object.defineProperty() 是重写对象的key,而 Proxy 只是拦截读写操作。

Vue3采用 懒代理 解决深度嵌套问题,只需要遍历第一层的属性即可!

function reactive(data) {
    return new Proxy(data, {
        get(target, key, receiver) {
            var res = Reflect.get(target, key, receiver);
            if(typeof ref == 'object') {
                return reactive(res);   // 懒代理
            }
            return res;
        },
        set(target, key, value, receiver) {
            return Reflect.get(target, key, value, receiver);
        }
    })
}

对数组做插入、删除、排序操作时,仍然会多次触发 Proxy getter/setter,那么 Vue3 中做了什么优化呢?

相关文章

网友评论

      本文标题:回顾Vue2,面向Vue3

      本文链接:https://www.haomeiwen.com/subject/epfrkktx.html