浅析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 相关文章推荐
IE event.srcElement和FF event.target 功能比较
Mar 01 Javascript
IE6/7/8中Option元素未设value时Select将获取空字符串
Apr 07 Javascript
js+css简单实现网页换肤效果
Dec 29 Javascript
js计算系统当前日期是星期几的方法
Jul 14 Javascript
jQuery validata插件实现方法
Jun 25 jQuery
jQuery实现节点的追加、替换、删除、复制功能示例
Jul 11 jQuery
微信小程序tabBar底部导航中文注解api详解
Aug 16 Javascript
浅谈JS中的反柯里化( uncurrying)
Aug 17 Javascript
微信小程序实现下拉菜单切换效果
Mar 30 Javascript
Node.js 实现远程桌面监控的方法步骤
Jul 02 Javascript
8个非常实用的Vue自定义指令
Dec 15 Vue.js
vue导入.md文件的步骤(markdown转HTML)
Dec 31 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
哪吒敖丙传:新人物二哥敖乙出场 小敖丙奶气十足
2020/03/08 国漫
教你如何把一篇文章按要求分段
2006/10/09 PHP
mysql5详细安装教程
2007/01/15 PHP
php5.2.0内存管理改进
2007/01/22 PHP
PHP 处理TXT文件(打开/关闭/检查/读取)
2013/05/13 PHP
PHP实现将textarea的值根据回车换行拆分至数组
2015/06/10 PHP
PHP实现简单计算器小程序
2020/08/28 PHP
使用prototype.js 的时候应该特别注意的几个问题.
2007/04/12 Javascript
原生js实现复制对象、扩展对象 类似jquery中的extend()方法
2014/08/30 Javascript
ECMAScript5(ES5)中bind方法使用小结
2015/05/07 Javascript
JS如何实现文本框随文本的长度而增长
2015/07/30 Javascript
js右下角弹出提示框示例代码
2016/01/12 Javascript
ES6新特征数字、数组、字符串
2016/10/01 Javascript
js仿搜狐视频记录片列表展示效果
2020/05/30 Javascript
纯js模仿windows系统日历
2017/02/04 Javascript
JavaScript表单验证实现代码
2017/05/22 Javascript
关于echarts在节点显示动态数据及添加提示文本所遇到的问题
2018/04/20 Javascript
javascript设计模式 ? 建造者模式原理与应用实例分析
2020/04/10 Javascript
跟老齐学Python之总结参数的传递
2014/10/10 Python
Python去除字符串两端空格的方法
2015/05/21 Python
python实现list元素按关键字相加减的方法示例
2017/06/09 Python
Python根据指定日期计算后n天,前n天是哪一天的方法
2018/05/29 Python
python实现可逆简单的加密算法
2019/03/22 Python
data:image data url 文件转为Blob上传后端的方法
2019/07/16 HTML / CSS
Staples英国官方网站:办公用品一站式采购
2017/10/06 全球购物
Looking4Parking美国:全球排名第一的机场停车比较品牌
2019/08/26 全球购物
托管代码(Managed Code)和非托管代码(Unmanaged Code)有什么区别
2014/09/29 面试题
40岁生日感言
2014/02/15 职场文书
《鸟的天堂》教学反思
2014/02/27 职场文书
新年团拜会主持词
2014/04/02 职场文书
大学生学雷锋活动总结
2014/06/26 职场文书
强烈推荐:小学生:暑假作息时间表(值得收藏)
2019/07/09 职场文书
导游词之西安骊山
2019/12/20 职场文书
导游词之昭君岛
2020/01/17 职场文书
CI Games宣布《堕落之王2》使用虚幻引擎5制作 预计将于2023年正式发售
2022/04/11 其他游戏
win10电脑右下角输入法图标不见了?Win10右下角不显示输入法的解决方法
2022/07/23 数码科技