浅析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 String 的扩展方法集合
Jun 01 Javascript
Js日期选择器并自动加入到输入框中示例代码
Aug 02 Javascript
JavaScript运行时库属性一览表
Mar 14 Javascript
一个简单的全屏图片上下打开显示网页效果示例
Jul 08 Javascript
基于JS实现Android,iOS一个手势动画效果
Apr 27 Javascript
angular.js 路由及页面传参示例
Feb 24 Javascript
js清除浏览器缓存的几种方法
Mar 15 Javascript
jquery学习笔记之无new构建详解
Dec 07 jQuery
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
Aug 25 Javascript
JavaScript类型相关的常用操作总结
Feb 14 Javascript
基于Vue实现的多条件筛选功能的详解(类似京东和淘宝功能)
May 07 Javascript
Vue实现 点击显示再点击隐藏效果(点击页面空白区域也隐藏效果)
Jan 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
main.php
2006/12/09 PHP
mysql_connect localhost和127.0.0.1的区别(网络层阐述)
2015/03/26 PHP
PHP将Excel导入数据库及数据库数据导出至Excel的方法
2015/06/24 PHP
php+webSoket实现聊天室示例代码(附源码)
2017/02/17 PHP
关于laravel 数据库迁移中integer类型是无法指定长度的问题
2019/10/09 PHP
全面理解面向对象的 JavaScript(来自ibm)
2013/11/10 Javascript
如何让浏览器支持jquery ajax load 前进、后退功能
2014/06/12 Javascript
HTML,CSS,JavaScript速查表推荐
2014/12/02 Javascript
Angular用来控制元素的展示与否的原生指令介绍
2015/01/07 Javascript
javascript批量修改文件编码格式的方法
2015/01/27 Javascript
JavaScript中几种排序算法的简单实现
2015/07/29 Javascript
JavaScript模版引擎的基本实现方法浅析
2016/02/15 Javascript
HTML Table 空白单元格补全的简单实现
2016/10/13 Javascript
Jquery中attr与prop的区别详解
2017/05/27 jQuery
jquery ajax异步提交表单数据的方法
2017/10/27 jQuery
create-react-app构建项目慢的解决方法
2018/03/14 Javascript
layer.open关闭父窗口 以及调用父页面的方法
2018/08/17 Javascript
JS防抖和节流实例解析
2019/09/24 Javascript
js实现点赞效果
2020/03/16 Javascript
vue路由结构可设一层方便动态添加路由操作
2020/08/31 Javascript
[47:48]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第三局
2016/02/28 DOTA
详解Python中的条件判断语句
2015/05/14 Python
python多线程socket编程之多客户端接入
2017/09/12 Python
python对于requests的封装方法详解
2019/01/03 Python
python 类的继承 实例方法.静态方法.类方法的代码解析
2019/08/23 Python
世界最大的私人旅行指南出版商:孤独星球
2016/08/23 全球购物
日本面向世界,国际级的免税在线购物商城:DOKODEMO
2017/02/01 全球购物
加拿大在线旅游公司:Flighthub
2019/03/11 全球购物
男方父母婚礼答谢词
2014/01/25 职场文书
房地产广告策划方案
2014/05/15 职场文书
材料成型及控制工程专业求职信
2014/06/19 职场文书
2014年度个人工作总结
2014/11/07 职场文书
导游词之山西-五老峰
2019/10/07 职场文书
MySQL 表空间碎片的概念及相关问题解决
2021/05/07 MySQL
springboot 自定义配置 解决Boolean属性不生效
2022/03/18 Java/Android
彻底卸载VMware虚拟机的超详细步骤记录
2022/07/15 Servers