浅析Proxy可以优化vue的数据监听机制问题及实现思路


Posted in Javascript onNovember 29, 2018

我们首先来看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之所以要从新实现,主要有这几个原因:

  1. Object.defineProperty的性能开销。
  2. defineReactive一开始就要对要监听的对象所有属性都执行一遍,因为传统方法要将一个对象转换成可监听对象,只能如此。
  3. 添加删除属性的问题。
  4. 还有一点就是这个模块被耦合到了vue里面,新版本可以单独作为一个库来使用。

然后我们来看看同样的功能采用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;

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

总结

以上所述是小编给大家介绍的Proxy可以优化vue的数据监听机制问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript变量作用域使用中常见错误总结
Mar 26 Javascript
js拖动div 当鼠标移动时整个div也相应的移动
Nov 21 Javascript
JS控制弹出新页面窗口位置和大小的方法
Mar 02 Javascript
JavaScript地理位置信息API
Jun 11 Javascript
过期软件破解办法实例详解
Jan 04 Javascript
js模态对话框使用方法详解
Feb 16 Javascript
Vue实现本地购物车功能
Dec 05 Javascript
JS栈stack类的实现与使用方法示例
Jan 31 Javascript
小程序云开发获取不到数据库记录的解决方法
May 18 Javascript
vue+element实现打印页面功能
May 20 Javascript
JS去除字符串最后的逗号实例分析【四种方法】
Jun 20 Javascript
Vue中的循环及修改差值表达式的方法
Aug 29 Javascript
vue实现双向绑定和依赖收集遇到的坑
Nov 29 #Javascript
js中this的指向问题归纳总结
Nov 28 #Javascript
基于vue实现移动端圆形旋钮插件效果
Nov 28 #Javascript
VUE2.0 ElementUI2.0表格el-table自适应高度的实现方法
Nov 28 #Javascript
Vue触发式全局组件构建的方法
Nov 28 #Javascript
Vue axios全局拦截 get请求、post请求、配置请求的实例代码
Nov 28 #Javascript
jQuery实现购物车的总价计算和总价传值功能
Nov 28 #jQuery
You might like
CI框架中zip类应用示例
2014/06/17 PHP
PHP中iconv函数转码时截断字符问题的解决方法
2015/01/21 PHP
详解如何在云服务器上部署Laravel
2017/06/30 PHP
深入理解Yii2.0乐观锁与悲观锁的原理与使用
2017/07/26 PHP
如何解决PHP获取不到SESSION信息之一般情况
2019/10/10 PHP
jquery查找父元素、子元素(个人经验总结)
2014/04/09 Javascript
谷歌浏览器不支持showModalDialog模态对话框的解决方法
2014/09/22 Javascript
浅谈轻量级js模板引擎simplite
2015/02/13 Javascript
jQuery制作效果超棒的手风琴折叠菜单
2015/04/03 Javascript
JS中Json数据的处理和解析JSON数据的方法详解
2016/06/29 Javascript
jQuery+HTML5实现WebGL高性能烟花绽放动画效果【附demo源码下载】
2017/08/18 jQuery
Vue2.0中集成UEditor富文本编辑器的方法
2018/03/03 Javascript
原生实现一个react-redux的代码示例
2018/06/08 Javascript
angular6.0开发教程之如何安装angular6.0框架
2018/06/29 Javascript
Angular刷新当前页面的实现方法
2018/11/21 Javascript
WebGL three.js学习笔记之阴影与实现物体的动画效果
2019/04/25 Javascript
JS实现水平遍历和嵌套递归操作示例
2019/08/15 Javascript
Python实现破解猜数游戏算法示例
2017/09/25 Python
python遍历文件夹下所有excel文件
2018/01/03 Python
详解【python】str与json类型转换
2019/04/29 Python
Python 从subprocess运行的子进程中实时获取输出的例子
2019/08/14 Python
TensorFlow梯度求解tf.gradients实例
2020/02/04 Python
python实现暗通道去雾算法的示例
2020/09/27 Python
python Matplotlib数据可视化(2):详解三大容器对象与常用设置
2020/09/30 Python
美国旅游网站:Tours4Fun
2017/02/17 全球购物
美国体育用品商店:Rally House(NCAA、NFL、MLB、NBA、NHL和MLS)
2018/01/03 全球购物
韩国演唱会订票网站:StubHub韩国
2019/01/17 全球购物
纪念建党演讲稿范文
2014/01/13 职场文书
设计师个人求职信范文
2014/02/02 职场文书
大学生学年自我鉴定
2014/02/10 职场文书
个人简历中自我评价
2014/02/11 职场文书
感恩教师节演讲稿
2014/09/03 职场文书
2014学生会工作总结报告
2014/12/02 职场文书
2016年助残日旅游活动总结
2016/04/01 职场文书
Python基础之元组与文件知识总结
2021/05/19 Python
生命的关键成分来自太空?陨石说是的
2022/04/29 数码科技