浅析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 相关文章推荐
二级域名或跨域共享Cookies的实现方法
Aug 07 Javascript
游览器中javascript的执行过程(图文)
May 20 Javascript
JavaScript中__proto__与prototype的关系深入理解
Dec 04 Javascript
JS实现自适应高度表单文本框的方法
Feb 25 Javascript
简单的js表格操作
Sep 24 Javascript
node.js 中间件express-session使用详解
May 20 Javascript
详解vue-cli 脚手架项目-package.json
Jul 04 Javascript
ECMAScript6变量的解构赋值实例详解
Sep 19 Javascript
vue+echarts实现可拖动节点的折线图(支持拖动方向和上下限的设置)
Apr 12 Javascript
个人小程序接入支付解决方案
May 23 Javascript
VUE前后端学习tab写法实例
Aug 06 Javascript
JavaScript正则表达式验证登录实例
Mar 18 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
声音就能俘获人心,蕾姆,是哪个漂亮小姐姐配音呢?
2020/03/03 日漫
PHP小技巧搜集,每个PHPer都来露一手
2007/01/02 PHP
PHP插入排序实现代码
2013/04/04 PHP
深入解析Session是否必须依赖Cookie
2013/08/02 PHP
如何通过PHP实现Des加密算法代码实例
2020/05/09 PHP
几个比较实用的JavaScript 测试及效验工具
2010/04/18 Javascript
移动节点的jquery代码
2014/01/13 Javascript
JavaScript验证电子邮箱的函数
2014/08/22 Javascript
jQuery中click事件用法实例
2014/12/26 Javascript
js同源策略详解
2015/05/21 Javascript
JavaScript获取两个数组交集的方法
2015/06/09 Javascript
JavaScript中利用jQuery绑定事件的几种方式小结
2016/03/06 Javascript
BootStrap响应式导航条实例介绍
2016/05/06 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
2016/10/14 Javascript
JAVA Web实时消息后台服务器推送技术---GoEasy
2016/11/04 Javascript
js调用屏幕宽度的简单方法
2016/11/14 Javascript
jQuery实现二维码扫描功能
2017/01/09 Javascript
JS实现简单的天数计算器完整实例
2017/04/28 Javascript
深入理解Node中的buffer模块
2017/06/03 Javascript
JS实现显示当前日期的实例代码
2018/07/03 Javascript
详解vue 项目白屏解决方案
2018/10/31 Javascript
详解基于mpvue微信小程序下载远程图片到本地解决思路
2019/05/16 Javascript
JavaScript冒泡算法原理与实现方法深入理解
2020/06/04 Javascript
vue 中使用print.js导出pdf操作
2020/11/13 Javascript
[00:47]TI7不朽珍藏III——沙王不朽展示
2017/07/15 DOTA
Flask SQLAlchemy一对一,一对多的使用方法实践
2013/02/10 Python
简单介绍Python中的decode()方法的使用
2015/05/18 Python
python使用opencv进行人脸识别
2017/04/07 Python
python 判断参数为Nonetype类型或空的实例
2018/10/30 Python
Python shutil模块用法实例分析
2019/10/02 Python
小学教师培训感言
2014/02/11 职场文书
给全校老师的建议书
2014/03/13 职场文书
中学生寄语大全
2014/04/03 职场文书
2014院党委领导班子及其成员群众路线对照检查材料思想汇报
2014/10/04 职场文书
工程质检员岗位职责
2015/04/08 职场文书
以MySQL5.7为例了解一下执行计划
2022/04/13 MySQL