浅析Proxy可以优化vue的数据监听机制问题及实现思路
我们首先来看vue2.x中的实现,为简单起见,我们这里不考虑多级嵌套,也不考虑数组
vue2.x中的实现
其本质是newWatcher(data,key,callback)的方式,而在调用之前是先将data中的所有属性转化成可监听的对象,其主要就是利用Object.defineProperty,。
classWatcher{ constructor(data,key,cb){ } } //转换成可监听对象 functionobserve(data){ newObserver(data) } //修改数据的getter和setter functiondefineReactive(obj,key){ letvalue=obj[key]; Object.defineProperty(obj,key,{ enumerable:true, configurable:true, get(){ returnvalue; }, set(newVal){ value=newVal } }) }
Observer的实现很简单
classObserver{ constructor(data){ this.walk(data); } walk(data){ for(varkeyindata){ //这里不考虑嵌套的问题,否则的话需要递归调用walk defineReactive(data,key) } } }
现在怎么将watcher和getter/setter联系起来,vue的方法是添加一个依赖类:Dep
classWatcher{ constructor(data,key,cb){ this.cb=cb; Dep.target=this;//每次新建watcher的时候讲给target赋值,对target的管理这里简化了vue的实现 data[key];//调用getter,执行addSub,将target传入对应的dep;vue的实现本质就是如此 } } classDep{ constructor(){ this.subs=[]; } addSub(sub){ this.subs.push(sub); } notify(){ this.subs.forEach(sub=>sub.cb()) } } functiondefineReactive(obj,key){ letvalue=obj[key]; letdep=newDep();//每一个属性都有一个对应的dep,作为闭包保存 Object.defineProperty(obj,key,{ enumerable:true, configurable:true, get(){ dep.addSub(Dep.target) Dep.target=null; returnvalue; }, set(newVal){ value=newVal dep.notify(); } }) }
以上就是vue的思路,vue3之所以要从新实现,主要有这几个原因:
- Object.defineProperty的性能开销。
- defineReactive一开始就要对要监听的对象所有属性都执行一遍,因为传统方法要将一个对象转换成可监听对象,只能如此。
- 添加删除属性的问题。
- 还有一点就是这个模块被耦合到了vue里面,新版本可以单独作为一个库来使用。
然后我们来看看同样的功能采用Proxy会怎样实现。
Proxy的实现
将一个对象转换成Proxy的方式很简单,只需要作为参数传给proxy即可;
classWatcher{ constructor(proxy,key,cb){ this.cb=cb; Dep.target=this; this.value=proxy[key]; } } classDep{ constructor(){ this.subs=[] } addSub(sub){ this.subs.push(sub); } notify(newVal){ this.subs.forEach(sub=>{ sub.cb(newVal,sub.value); sub.value=newVal; }) } } constobserve=(obj)=>{ constdeps={}; returnnewProxy(obj,{ get:function(target,key,receiver){ constdep=(deps[key]=deps[key]||newDep); Dep.target&&dep.addSub(Dep.target) Dep.target=null; returnReflect.get(target,key,receiver); }, set:function(target,key,value,receiver){ constdep=(deps[key]=deps[key]||newDep); Promise.resolve().then(()=>{ dep.notify(value); }) returnReflect.set(target,key,value,receiver); } }); } varstate=observe({x:0}) newWatcher(state,'x',function(n,o){ console.log(n,o) }); newWatcher(state,'y',function(n,o){ console.log(n,o) }); state.x=3; state.y=3;
也许一开始我们只关心x和y,那么就不会对其他的属性做相应的处理,除非添加watcher,其他时间target都是null
总结
以上所述是小编给大家介绍的Proxy可以优化vue的数据监听机制问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!