浅析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 XML数据显示为HTML一例
Dec 23 Javascript
javascript学习笔记(十九) 节点的操作实现代码
Jun 20 Javascript
js统计页面的来访次数实现代码
May 09 Javascript
判断iframe里的页面是否加载完成
Jun 06 Javascript
jquery实现动态操作select选中
Feb 11 Javascript
理解Javascript的call、apply
Dec 16 Javascript
JS基于HTML5的canvas标签实现炫目的色相球动画效果实例
Aug 24 Javascript
js制作网站首页图片轮播特效代码
Aug 30 Javascript
关于vue.js组件数据流的问题
Jul 26 Javascript
Angular4 组件通讯方法大全(推荐)
Jul 12 Javascript
jQuery实现滑动星星评分效果(每日分享)
Nov 13 jQuery
vue 封装面包屑组件教程
Nov 16 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
DOTA2 无惧惊涛骇浪 昆卡大型水友攻略
2020/04/20 DOTA
PHP var_dump遍历对象属性的函数与应用代码
2010/06/04 PHP
PHP进程同步代码实例
2015/02/12 PHP
PHP简单实现数字分页功能示例
2016/08/24 PHP
php对mongodb的扩展(初识如故)
2012/11/11 Javascript
jQuery 网易相册鼠标移动显示隐藏效果实现代码
2013/03/31 Javascript
jquery中html、val与text三者属性取值的联系与区别介绍
2013/12/29 Javascript
javascript截取字符串小结
2015/04/28 Javascript
JavaScript实现DOM对象选择器
2016/09/24 Javascript
JavaScript之WebSocket技术详解
2016/11/18 Javascript
prototype与__proto__区别详细介绍
2017/01/09 Javascript
基于JS实现网页中的选项卡(两种方法)
2017/06/16 Javascript
js中let和var定义变量的区别
2018/02/08 Javascript
11行JS代码制作二维码生成功能
2018/03/09 Javascript
Electron中实现大文件上传和断点续传功能
2018/10/28 Javascript
详解webpack打包后如何调试的方法步骤
2018/11/07 Javascript
如何封装了一个vue移动端下拉加载下一页数据的组件
2019/01/06 Javascript
Vue双向绑定实现原理与方法详解
2020/05/07 Javascript
使用Vue+Django+Ant Design做一个留言评论模块的示例代码
2020/06/01 Javascript
python发送邮件实例分享
2017/07/28 Python
Python内建模块struct实例详解
2018/02/02 Python
Python使用ConfigParser模块操作配置文件的方法
2018/06/29 Python
python获取微信小程序手机号并绑定遇到的坑
2018/11/19 Python
python实现键盘输入的实操方法
2019/07/16 Python
Python socket实现的文件下载器功能示例
2019/11/15 Python
浅析python中while循环和for循环
2019/11/19 Python
python爬取网易云音乐热歌榜实例代码
2020/08/07 Python
周仰杰(JIMMY CHOO)法国官方网站:闻名世界的鞋子品牌
2019/09/27 全球购物
七一党建活动方案
2014/01/28 职场文书
两只小狮子教学反思
2014/02/05 职场文书
《找不到快乐的波斯猫》教学反思
2014/02/24 职场文书
公司年终奖分配方案
2014/06/16 职场文书
课前一分钟演讲稿
2014/08/26 职场文书
党员剖析材料范文
2014/09/30 职场文书
鲁迅故里导游词
2015/02/05 职场文书
学校就业保障协议书
2019/06/24 职场文书