浅析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 相关文章推荐
获取页面高度,窗口高度,滚动条高度等参数值getPageSize,getPageScroll
Sep 22 Javascript
菜鸟javascript基础整理1
Dec 06 Javascript
浅析js封装和作用域
Jul 09 Javascript
Javascript倒计时页面跳转实例小结
Sep 11 Javascript
node.js中使用q.js实现api的promise化
Sep 17 Javascript
超级给力的JavaScript的React框架入门教程
Jul 02 Javascript
Angular企业级开发——MVC之控制器详解
Feb 20 Javascript
jQuery给表格添加分页效果
Mar 02 Javascript
浅谈Angular 中何时取消订阅
Nov 22 Javascript
Vue中的$set的使用实例代码
Oct 08 Javascript
Vue实现简单分页器
Dec 29 Javascript
小程序自定义单页面、全局导航栏的实现代码
Mar 15 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+mysql开源XNA 聚合程序发布 下载
2007/07/13 PHP
24条货真价实的PHP代码优化技巧
2016/07/28 PHP
PHP简单实现数字分页功能示例
2016/08/24 PHP
jQuery的缓存机制浅析
2014/06/07 Javascript
javascript检测浏览器的缩放状态实现代码
2014/09/28 Javascript
AngularJS基础学习笔记之表达式
2015/05/10 Javascript
js实现动态创建的元素绑定事件
2016/07/19 Javascript
详解nodejs微信公众号开发——1.接入微信公众号
2017/04/10 NodeJs
详解Vue-cli webpack移动端自动化构建rem问题
2018/04/07 Javascript
微信小程序实现自定义加载图标功能
2018/07/19 Javascript
[04:07]显微镜下的DOTA2第八期——英雄复活动作
2014/06/24 DOTA
[46:55]完美世界DOTA2联赛决赛 FTD vs Phoenix 第三场 11.08
2020/11/11 DOTA
Python实现方便使用的级联进度信息实例
2015/05/05 Python
python实现支付宝当面付(扫码支付)功能
2018/05/30 Python
python实现梯度下降算法
2020/03/24 Python
Python爬虫设置代理IP(图文)
2018/12/23 Python
python-tkinter之按钮的使用,开关方法
2019/06/11 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
2019/08/13 Python
解决在pycharm运行代码,调用CMD窗口的命令运行显示乱码问题
2019/08/23 Python
基于Python新建用户并产生随机密码过程解析
2019/10/08 Python
使用python计算三角形的斜边例子
2020/04/15 Python
Python实现爬取并分析电商评论
2020/06/19 Python
如何在pycharm中安装第三方包
2020/10/27 Python
基于Django快速集成Echarts代码示例
2020/12/01 Python
HTML5 video 视频标签使用介绍
2014/02/03 HTML / CSS
布鲁明戴尔百货店:Bloomingdale’s
2016/12/21 全球购物
司法局群众路线教育实践活动开展情况总结
2014/10/25 职场文书
财务人员岗位职责
2015/02/03 职场文书
运动会入场词
2015/07/18 职场文书
廉洁自律心得体会2016
2016/01/13 职场文书
浅谈Java实现分布式事务的三种方案
2021/06/11 Java/Android
python机器学习Github已达8.9Kstars模型解释器LIME
2021/11/23 Python
P站美图推荐——变身女主角特辑
2022/03/20 日漫
唤醒紫霞仙子,携手再游三界!大话手游X《大话西游》电影合作专属剧情任务
2022/04/03 其他游戏
vue elementUI表格控制对应列
2022/04/13 Vue.js