为什么Proxy可以优化vue的数据监听机制

栏目: JavaScript · 发布时间: 5年前

内容简介:我们首先来看vue2.x中的实现,为简单起见,我们这里不考虑多级嵌套,也不考虑数组其本质是Observer的实现很简单

我们首先来看vue2.x中的实现,为简单起见,我们这里不考虑多级嵌套,也不考虑数组

vue2.x中的实现

其本质是 new Watcher(data, key, callback) 的方式,而在调用之前是先将data中的所有属性转化成可监听的对象, 其主要就是利用 Object.defineProperty ,。

class Watcher{
    constructor(data, key, cb){

    }
}
//转换成可监听对象
function observe(data){
    new Observer(data)
}

//修改数据的getter和setter
function defineReactive(obj, key){
    let value = obj[key];
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get(){
            return value;
        },
        set(newVal){
            value = newVal
        }
    })
}
复制代码

Observer的实现很简单

class Observer {
    constructor(data){
        this.walk(data);
    }

    walk(data){
        for(var key in data) {
            // 这里不考虑嵌套的问题,否则的话需要递归调用walk
            defineReactive(data, key)
        }
    }
}
复制代码

现在怎么将watcher和getter/setter联系起来,vue的方法是添加一个依赖类:Dep

class Watcher{
    constructor(data, key, cb){
        this.cb = cb;
        Dep.target = this; //每次新建watcher的时候讲给target赋值,对target的管理这里简化了vue的实现
        data[key];//调用getter,执行addSub, 将target传入对应的dep; vue的实现本质就是如此
    }
}
class Dep {
    constructor(){
        this.subs = [];
    }
    addSub(sub){
        this.subs.push(sub);
    }
    notify(){
        this.subs.forEach(sub => sub.cb())
    }
}
function defineReactive(obj, key){
    let value = obj[key];
    let dep = new Dep(); //每一个属性都有一个对应的dep,作为闭包保存
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get(){
            dep.addSub(Dep.target)
            Dep.target = null;
            return value;
        },
        set(newVal){
            value = newVal
            dep.notify();
        }
    })
}
复制代码

以上就是vue的思路,vue3之所以要从新实现,主要有这几个原因:

Object.defineProperty
defineReactive

然后我们来看看同样的功能采用Proxy会怎样实现。

Proxy的实现

将一个对象转换成Proxy的方式很简单,只需要作为参数传给proxy即可;

class Watcher {
    constructor(proxy, key, cb) {
        this.cb = cb;
        Dep.target = this;
        this.value = proxy[key];
    }
}

class Dep {
    constructor(){
        this.subs = []
    }
    addSub(sub){
        this.subs.push(sub);
    }
    notify(newVal){
        this.subs.forEach(sub => {
            sub.cb(newVal, sub.value);
            sub.value = newVal;
        })
    }
}

const observe = (obj) => {
    const deps = {};
    return new Proxy(obj, {
        get: function (target, key, receiver) {
            const dep = (deps[key] = deps[key] || new Dep);
            Dep.target && dep.addSub(Dep.target)
            Dep.target = null;
            return Reflect.get(target, key, receiver);
        },
        set: function (target, key, value, receiver) {
            const dep = (deps[key] = deps[key] || new Dep);
            Promise.resolve().then(() => {
                dep.notify(value);
            })
            return Reflect.set(target, key, value, receiver);
        }
    });
}

var state = observe({x:0})
new Watcher(state, 'x', function(n, o){
    console.log(n, o)
});
new Watcher(state, 'y', function(n, o){
    console.log(n, o)
});
state.x = 3;
state.y = 3;
复制代码

也许一开始我们只关心 xy ,那么就不会对其他的属性做相应的处理,除非添加watcher,其他时间target都是null

如果有什么错误请指正,谢谢。


以上所述就是小编给大家介绍的《为什么Proxy可以优化vue的数据监听机制》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective JavaScript

Effective JavaScript

David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99

"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具