浅析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 控制小数位数的实现代码
Aug 02 Javascript
动态载入js提高网页打开速度的方法
Jul 04 Javascript
javascript自定义函数参数传递为字符串格式
Jul 29 Javascript
javascript搜索框点击文字消失失焦时文本出现
Sep 18 Javascript
炫酷的js手风琴效果
Oct 13 Javascript
vue中实现移动端的scroll滚动方法
Mar 03 Javascript
微信小程序动态生成二维码的实现代码
Jul 25 Javascript
Vue使用zTree插件封装树组件操作示例
Apr 25 Javascript
微信网页登录逻辑与实现方法
Apr 29 Javascript
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 jQuery
vue使用混入定义全局变量、函数、筛选器的实例代码
Jul 29 Javascript
node.js 微信开发之定时获取access_token
Feb 07 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
ThinkPHP3.1新特性之内容解析输出详解
2014/06/19 PHP
destoon实现会员商铺中指定会员或会员组投放广告的方法
2014/08/21 PHP
PHP实现的敏感词过滤方法示例
2019/03/06 PHP
PHP7 标准库修改
2021/03/09 PHP
JS效率个人经验谈(8-15更新),加入range技巧
2007/01/09 Javascript
13 个JavaScript 性能提升技巧分享
2012/07/26 Javascript
js防止表单重复提交实现代码
2012/09/05 Javascript
Js实现滚动变色的文字效果
2014/06/16 Javascript
JavaScript使用focus()设置焦点失败的解决方法
2014/09/03 Javascript
Javascript保存网页为图片借助于html2canvas库实现
2014/09/05 Javascript
2014年最火的Node.JS后端框架推荐
2014/10/27 Javascript
JS控制表格实现一条光线流动分割行的方法
2015/03/09 Javascript
Node.js巧妙实现Web应用代码热更新
2015/10/22 Javascript
jQuery表格插件datatables用法汇总
2016/03/29 Javascript
基于 Node.js 实现前后端分离
2016/04/23 Javascript
jQuery原理系列-常用Dom操作详解
2016/06/07 Javascript
VUEJS实战之修复错误并且美化时间(2)
2016/06/13 Javascript
AngularJS延迟加载html template
2016/07/27 Javascript
基于node.js实现微信支付退款功能
2017/12/19 Javascript
解决vue同一slot在组件中渲染多次的问题
2018/09/06 Javascript
Vue中Table组件Select的勾选和取消勾选事件详解
2019/03/19 Javascript
vue实现菜单切换功能
2019/05/08 Javascript
生产制造追溯系统之再说条码打印
2019/06/03 Javascript
浅谈一个webpack构建速度优化误区
2019/06/24 Javascript
使用python实现省市三级菜单效果
2016/01/20 Python
Windows下搭建python开发环境详细步骤
2020/07/20 Python
Python3匿名函数用法示例
2018/07/25 Python
5分钟 Pipenv 上手指南
2018/12/20 Python
Python SSL证书验证问题解决方案
2020/01/13 Python
波兰品牌内衣及泳装网上商店:Astratex.pl
2017/02/03 全球购物
Agoda香港:全球特价酒店预订
2017/05/07 全球购物
百思买加拿大:Best Buy Canada
2018/03/20 全球购物
运动会稿件50字
2014/02/17 职场文书
群众路线领导班子四风对照检查材料
2014/09/27 职场文书
社区六一儿童节活动总结
2015/02/11 职场文书
美丽心灵观后感
2015/06/01 职场文书