记一次比较Vue2和Vue3响应式原理和性能差异

前端人

共 5005字,需浏览 11分钟

 ·

2021-03-02 12:48


关注公众号 前端人,回复“加群

添加无广告优质学习群

写在前面

Vue响应式原理是数据驱动视图的核心,它能够自动帮助开发者监听数据的变化,最终触发视图更新。它是Vue的渲染更新过程的核心。

那么了解这一部分的原理至关重要,这篇文章就结合vue2和vue3响应式来做一个对比,既明白了响应式原理的实现,又对比了二者在性能上的差异~

需要了解的api

这篇文章不是零基础,需要对一些基础api有一定的了解,那么这里给出这些api的官方文档,供大家参考学习:

  • vue2响应式原理
  • Object.defineProperty
  • vue3响应式原理
  • Proxy
  • Reflect

准备一个原始对象数据

为了做这个实验,我使用同一个数据对象来分别做vue2和vue3的示例:注意这个data数据从最外层花括弧到最里层总共8个层级,你可以数一下。

const data = {
    username'tom',
    profile: {
        city'beijing',
        a: {
            b12,
            c: {
                d23
            }
        }
    }
}

接下来我分别写点代码对这个数据做响应式处理:

vue2

const data = {
  username"tom",
  profile: {
    city"beijing",
    a: {
      b12,
      c: {
        d23,
      },
    },
  },
};
function observe(data{
  console.log(1);
  if (typeof data !== "object" || data == null) {
    return data;
  }
  for (const key in data) {
    defineReactive(data, key, data[key]);
  }
}

function defineReactive(target, key, val{
  observe(val);
  Object.defineProperty(target, key, {
    get() {
      console.log(`get ${key}`);
      return val;
    },
    set(newValue) {
      console.log(`set ${key}`);
      if (newValue !== val) {
        observe(newValue);
        val = newValue;
      }
    },
  });
}
observe(data);
console.log(data);

打印的结果如下:

从图中可以清晰的看到总共打印了8次1,也就是说observe一共执行了8次;由此可见vue2是一次递归到底的来实现响应式的,好接下来看看vue3:

vue3

function observe(data{
  console.log(1);
  if (typeof data !== "object" || data == null) {
    return data;
  }
  const p = new Proxy(data, {
    get(target, key, receiver) {
      console.log(`get ${key}`);
      const result = Reflect.get(data, key, receiver);
      // 当获取值的是时候 再设置响应式
      return observe(result);
    },
    set(target, key, val, receiver) {
      console.log(`set ${key}`);
      const result = Reflect.set(target, key, val, receiver);
      return result;
    },
  });
  return p;
}

const data = {
  username"tom",
  profile: {
    city"beijing",
    a: {
      b12,
      c: {
        d23,
      },
    },
  },
};

const p1 = observe(data);
console.log(p1);

打印结果如图:

只打印了一次1,也就是说observe只执行了一次,从代码可以看出,将来执行get的时候,observe又会再次执行。什么意思呢?也就是说Vue3对于数据的深层监听只有当获取值的时候才会响应式处理,这样在性能上肯定会提升很多。争议

读到这里,抛开其他细节来讲,可能你会来句卧槽,那Vue2也可以在get的时候observe啊,确实如此,但是想一下是不是会有点问题呢?问题就在于每次执行get的时候,不管是获取哪个属性,都需要执行一下observe,并且它还是会向下遍历,这样增加了时间复杂度,可想而之,其性能是多么浪费的,还不如一次性深度监听到底呢?

而proxy则不一样,它只会响应式处理你get的那个层级,它不会深度遍历,这样解释你明白了吗?

总结

接下来总结一下二者响应式的差异

  • Object.defineProperty
  1. 深度监听,性能问题
  2. 新增删除属性问题,这个可以参考我前面写的一个文章总结一下Vue那些常用必会面试必考的API,这里说明了vue2为什么需要set&delete两个api
  3. 数组问题,需要重写数组原型的几个方法
  • Proxy
  1. 性能提升了一大截
  2. 解决了vue2的那些问题
  3. 兼容性有待处理

当然示例代码都没做优化,实际上源码肯定是对各种情况还做了处理,这里就不做介绍了,可以自己去看源码哈~如果你对本文有什么看法或者觉得不对的地方,请在评论区赐教!共勉进步~~

原文:juejin.cn/post/6933953813657157646


  • 回复资料包领取我整理的进阶资料包
  • 回复加群,加入前端进阶群
  • console.log("点赞===看===你我都快乐"
  • Bug离我更远了,快乐离我更近了
浏览 101
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报