浅析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 相关文章推荐
js类后台管理菜单类-MenuSwitch
Sep 12 Javascript
jQuery autocomplete插件修改
Apr 17 Javascript
JavaScript高级程序设计(第3版)学习笔记12 js正则表达式
Oct 11 Javascript
阻止子元素继承父元素事件具体思路及实现
May 02 Javascript
去除html代码里面的script正则方法
May 19 Javascript
js中的eval()函数把含有转义字符的字符串转换成Object对象的方法
Dec 02 Javascript
详解自动生成博客目录案例
Dec 09 Javascript
原生JavaScript实现精美的淘宝轮播图效果示例【附demo源码下载】
May 27 Javascript
关于ES6箭头函数中的this问题
Feb 27 Javascript
详解Vue单元测试case写法
May 24 Javascript
Layui数据表格 前后端json数据接收的方法
Sep 19 Javascript
vue中实现点击空白区域关闭弹窗的两种方法
Dec 30 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
模拟OICQ的实现思路和核心程序(二)
2006/10/09 PHP
解决PHP4.0 和 PHP5.0类构造函数的兼容问题
2013/08/01 PHP
php读取纯真ip数据库使用示例
2014/01/26 PHP
destoon网站转移服务器后搜索汉字出现乱码的解决方法
2014/06/21 PHP
javascript IE中的DOM ready应用技巧
2008/07/23 Javascript
JS的千分位算法实现思路
2013/07/31 Javascript
jquery实现简单的二级导航下拉菜单效果
2015/09/07 Javascript
Bootstrap Validator 表单验证
2016/07/25 Javascript
D3.js实现雷达图的方法详解
2016/09/22 Javascript
vue.js单页面应用实例的简单实现
2017/04/10 Javascript
vue.js中过滤器的使用教程
2017/06/08 Javascript
jquery+css实现简单的图片轮播效果
2017/08/07 jQuery
react native与webview通信的示例代码
2017/09/25 Javascript
Node.js中,在cmd界面,进入退出Node.js运行环境的方法
2018/05/12 Javascript
详解vue-cli+es6引入es5写的js(两种方法)
2019/04/19 Javascript
使用JavaScript实现网页秒表功能(含开始、暂停、继续、重置功能)
2020/06/05 Javascript
如何正确解决VuePress本地访问出现资源报错404的问题
2020/12/03 Vue.js
[03:42]2016国际邀请赛中国区预选赛首日现场玩家采访
2016/06/26 DOTA
Python实现一个简单的MySQL类
2015/01/07 Python
Python实现文件复制删除
2016/04/19 Python
python中import学习备忘笔记
2017/01/24 Python
Python配置mysql的教程(推荐)
2017/10/13 Python
python编程嵌套函数实例代码
2018/02/11 Python
python实现log日志的示例代码
2018/04/28 Python
flask入门之文件上传与邮件发送示例
2018/07/18 Python
python时间序列按频率生成日期的方法
2019/05/14 Python
python经典趣味24点游戏程序设计
2019/07/26 Python
在Django下测试与调试REST API的方法详解
2019/08/29 Python
Python趣味入门教程之循环语句while
2020/08/26 Python
总经理助理岗位职责
2013/11/08 职场文书
公司出纳岗位职责
2013/12/07 职场文书
金融专业大学生自我评价
2014/01/09 职场文书
高中体育教学反思
2014/01/24 职场文书
幼儿园食品安全责任书
2015/05/08 职场文书
服装店员工管理制度
2015/08/07 职场文书
基层医务人员三严三实心得体会
2016/01/05 职场文书