浅析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 25 Javascript
调整小数的格式保留小数点后两位
May 14 Javascript
jquery获取当前元素索引值用法实例
Jun 10 Javascript
后端接收不到AngularJs中$http.post发送的数据原因分析及解决办法
Jul 05 Javascript
jQuery获取同级元素的简单代码
Jul 09 Javascript
JS锚点的设置与使用方法
Sep 05 Javascript
浅析javaScript中的浅拷贝和深拷贝
Feb 15 Javascript
详解Angular 自定义结构指令
Jun 21 Javascript
vue中v-for循环给标签属性赋值的方法
Oct 18 Javascript
浅谈Vuex的this.$store.commit和在Vue项目中引用公共方法
Jul 24 Javascript
js实现鼠标滑动到某个div禁止滚动
Sep 17 Javascript
js不常见操作运算符总结
Nov 20 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学习 字符串课件
2008/06/15 PHP
PHP表单递交控件名称含有点号(.)会被转化为下划线(_)的处理方法
2013/01/06 PHP
实现PHP框架系列文章(6)mysql数据库方法
2016/03/04 PHP
超棒的javascript页面顶部卷动广告效果
2007/12/01 Javascript
Ajax+Json 级联菜单实现代码
2009/10/27 Javascript
自己动手开发jQuery插件教程
2011/08/25 Javascript
Jqgrid之强大的表格插件应用
2015/12/02 Javascript
JS密码生成与强度检测完整实例(附demo源码下载)
2016/04/06 Javascript
JS对象是否拥有某属性如何判断
2017/02/03 Javascript
浅谈angularjs依赖服务注入写法的注意点
2017/04/24 Javascript
php 修改密码实现代码
2017/05/24 Javascript
Js实现京东无延迟菜单效果实例(demo)
2017/06/02 Javascript
Makefile/cmake/node-gyp中区分判断不同平台的方法
2018/12/18 Javascript
微信小程序开发问题之wx.previewImage
2018/12/25 Javascript
小程序使用wxs解决wxml保留2位小数问题
2019/12/13 Javascript
[00:37]食人魔魔法师轮盘吉兆顺应全新至宝将拥有额外款式
2019/12/19 DOTA
Eclipse + Python 的安装与配置流程
2013/03/05 Python
深入解析Python中的__builtins__内建对象
2016/06/21 Python
Python常见排序操作示例【字典、列表、指定元素等】
2018/08/15 Python
python实现烟花小程序
2019/01/30 Python
Python Web程序搭建简单的Web服务器
2019/07/31 Python
django实现web接口 python3模拟Post请求方式
2019/11/19 Python
使用NumPy读取MNIST数据的实现代码示例
2019/11/20 Python
python将数据插入数据库的代码分享
2020/08/16 Python
python如何编写类似nmap的扫描工具
2020/11/06 Python
婚鞋、新娘鞋、礼服鞋、童鞋:Nina Shoes
2019/09/04 全球购物
英国哈罗德园艺:Harrod Horticultural
2020/03/31 全球购物
EJB包括(SessionBean,EntityBean)说出他们的生命周期,及如何管理事务的?
2013/02/17 面试题
2014法院干警廉洁警示教育思想汇报
2014/09/13 职场文书
军训通讯稿范文
2015/07/18 职场文书
高一军训感想
2015/08/07 职场文书
学雷锋主题班会教案
2015/08/13 职场文书
如何书写公司员工保密协议?
2019/06/27 职场文书
家电创业计划书
2019/08/05 职场文书
JS异步堆栈追踪之为什么await胜过Promise
2021/04/28 Javascript
java Nio使用NioSocket客户端与服务端交互实现方式
2021/06/15 Java/Android