浅析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 相关文章推荐
asp.net和asp下ACCESS的参数化查询
Jun 11 Javascript
jqTransform美化表单
Oct 10 Javascript
使用JS批量选中功能实现更改数据库中的status状态值(批量展示)
Nov 22 Javascript
js canvas实现QQ拨打电话特效
May 10 Javascript
JS动态添加的div点击跳转到另一页面实现代码
Sep 30 Javascript
通过jquery.cookie.js实现记住用户名、密码登录功能
Jun 20 jQuery
jQuery实现的自定义轮播图功能详解
Dec 28 jQuery
vue双向绑定及观察者模式详解
Mar 19 Javascript
JavaScript 实现同时选取多个时间段的方法
Oct 17 Javascript
在微信小程序中使用mqtt服务的方法
Dec 13 Javascript
关于JavaScript回调函数的深入理解
Jun 27 Javascript
vue 数字翻牌器动态加载数据
Apr 20 Vue.js
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
PHP面向对象编程快速入门
2006/12/14 PHP
PHP多例模式介绍
2013/06/24 PHP
PHP下载生成的csv文件及问题总结
2015/08/06 PHP
Yii 2.0中场景的使用教程
2017/06/02 PHP
php实现银联商务公众号+服务窗支付的示例代码
2019/10/12 PHP
彪哥1.1(智能表格)提供下载
2006/09/07 Javascript
javascript 四则运算精度修正函数代码
2010/05/31 Javascript
用js来解决ajax读取页面乱码
2010/11/28 Javascript
JS实现网页表格自动变大缩小的方法
2015/03/09 Javascript
jquery使用remove()方法删除指定class子元素
2015/03/26 Javascript
javascript实现简单的全选和反选功能
2016/01/05 Javascript
详解nodejs微信jssdk后端接口
2017/05/25 NodeJs
JS表单提交验证、input(type=number) 去三角 刷新验证码
2017/06/21 Javascript
基于JavaScript实现选项卡效果
2017/07/21 Javascript
jquery点击回车键实现登录效果并默认焦点的方法
2018/03/09 jQuery
JS实现中英文混合文字溢出友好截取功能
2018/08/06 Javascript
vue-cli项目无法用本机IP访问的解决方法
2018/09/20 Javascript
vue element upload组件 file-list的动态绑定实现
2019/10/11 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
2020/09/16 Javascript
解决python3 安装完Pycurl在import pycurl时报错的问题
2018/10/15 Python
python使用xlsxwriter实现有向无环图到Excel的转换
2018/12/12 Python
Django项目中添加ldap登陆认证功能的实现
2019/04/04 Python
基于Pycharm加载多个项目过程图解
2020/01/19 Python
Python文字截图识别OCR工具实例解析
2020/03/05 Python
jupyter notebook tensorflow打印device信息实例
2020/04/20 Python
jupyter 添加不同内核的操作
2021/02/06 Python
amazeui页面校验功能的实现代码
2020/08/24 HTML / CSS
印度尼西亚最完整和最大的在线药房网站:Farmaku.com
2019/11/23 全球购物
main 函数执行以前,还会执行什么代码
2013/04/17 面试题
白酒业务员岗位职责
2013/12/27 职场文书
公司会计岗位职责
2014/02/13 职场文书
2015年元旦主持词结束语
2014/12/14 职场文书
入学证明
2015/06/23 职场文书
教务处干事工作总结
2015/08/14 职场文书
“学党章、守党纪、讲党规”学习心得体会
2016/01/14 职场文书
CSS3实现三角形不断放大效果
2021/04/13 HTML / CSS