浅析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 相关文章推荐
node.js中的console.timeEnd方法使用说明
Dec 09 Javascript
js实现精美的图片跟随鼠标效果实例
May 16 Javascript
js实现对ajax请求面向对象的封装
Jan 08 Javascript
JS实现求数组起始项到终止项之和的方法【基于数组扩展函数】
Jun 13 Javascript
快速理解 JavaScript 中的 LHS 和 RHS 查询的用法
Aug 24 Javascript
详解Vue中组件的缓存
Apr 20 Javascript
vue本地打开build后生成的dist文件夹index.html问题
Sep 04 Javascript
layui监听单元格编辑前后交互的例子
Sep 16 Javascript
微信小程序利用云函数获取手机号码
Dec 17 Javascript
Echarts实现单条折线可拖拽效果
Dec 19 Javascript
Vue使用富文本编辑器Vue-Quill-Editor(含图片自定义上传服务、清除复制粘贴样式等)
May 15 Javascript
Vue 解决通过this.$refs来获取DOM或者组件报错问题
Jul 28 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
PHP的单引号和双引号 字符串效率
2009/05/27 PHP
PHPnow安装服务[apache_pn]失败的问题的解决方法
2010/09/10 PHP
PHP实现一维数组转二维数组的方法
2015/02/25 PHP
PHP学习笔记(三):数据类型转换与常量介绍
2015/04/17 PHP
搭建基于Docker的PHP开发环境的详细教程
2015/07/01 PHP
Symfony2框架学习笔记之HTTP Cache用法详解
2016/03/18 PHP
PHP排序算法之快速排序(Quick Sort)及其优化算法详解
2018/04/21 PHP
js 使FORM表单的所有元素不可编辑的示例代码
2013/10/17 Javascript
JS之Date对象和获取系统当前时间详解
2014/01/13 Javascript
自定义jquery模态窗口插件无法在顶层窗口显示问题
2014/05/29 Javascript
jQuery多级手风琴菜单实例讲解
2015/10/22 Javascript
JS定时器用法分析【时钟与菜单中的应用】
2016/12/21 Javascript
angularjs 实现带查找筛选功能的select下拉框实例
2017/01/11 Javascript
微信小程序 PHP后端form表单提交实例详解
2017/01/12 Javascript
jQuery 实现图片的依次加载图片功能
2017/07/06 jQuery
关于jQuery里prev()的简单操作代码
2017/10/27 jQuery
JavaScript中.min.js和.js文件的区别讲解
2019/02/13 Javascript
通过实例了解js函数中参数的传递
2019/06/15 Javascript
webpack4 optimization使用总结
2019/11/10 Javascript
JavaScript数组及常见操作方法小结
2019/11/13 Javascript
JS获取表格视图所选行号的ids过程解析
2020/02/21 Javascript
vue-router为激活的路由设置样式操作
2020/07/18 Javascript
Python数据可视化正态分布简单分析及实现代码
2017/12/04 Python
PyQt QCombobox设置行高的方法
2019/06/20 Python
python+selenium select下拉选择框定位处理方法
2019/08/24 Python
Django中提示消息messages的设置方式
2019/11/15 Python
Python Sympy计算梯度、散度和旋度的实例
2019/12/06 Python
opencv resize图片为正方形尺寸的实现方法
2019/12/26 Python
pycharm 2019 最新激活方式(pycharm破解、激活)
2020/09/22 Python
Python3.x+pyqtgraph实现数据可视化教程
2020/03/14 Python
CSS3 实现弹跳的小球动画
2020/10/26 HTML / CSS
土木工程专业个人求职信
2013/12/30 职场文书
八一建军节活动方案
2014/02/10 职场文书
欢迎横幅标语
2014/06/17 职场文书
晚会主持人开场白台词
2015/05/28 职场文书
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers