vue3性能提升主要有哪些方面?(笔记)

153 阅读3分钟

1、编译阶段优化:VUE2每个组件实例都对应一个watcher实例,watcher实例会在组件渲染的过程中,把用到的数据property记录为依赖,当依赖发生变化触发setter通知到watcher从而使关联的组件重新渲染;

VUE3在编译阶段做了进一步优化:

1. diff算法中相比VUE2增加了静态标记,给发生变化的地方添加一个flag标记,下次发生变化的时候直接找到这个flag进行比较

2.静态提升(vue3对不参与更新的元素做了静态提升,他们只会被创建一次在渲染的时候直接复用,免去重复创
建,元素会被打上静态标记值-1,特殊标志是负整数,表示永远不会用于diff,VUE2时未参与更新的元素也在
render函数中,会重复创建阶段;)

3.事件监听缓存(默认情况下绑定事件行为,会被视为动态绑定【没开启事件监听器缓存】,所以每次都要追踪他的变化;开始事件侦听器缓存后,没有了静态标记,下次diff算法的时候直接用)

4.SSR优化:(在静态内容大到一定量级的时候,会使用createStaticVNode方法,
在客户端生成一staticNode,这些静态node会被直接innerHtml进去,就不需要创建对象再根据对象渲染)

2、源码体积更小:除了移除一些不常用的API,最重要的是treeshanking任何一个函数(如:ref、reavtived、conputed等)仅在用到时才打包,打包的整体体积更小

3、响应式系统:vue2采用defineproperty来劫持整个对象,然后深度遍历所有属性,给每个属性添加getter和setter实现响应式;vue3采用proxy重写了响应式系统,proxy可以对整个对象进行代理,所以不需要深度遍历,下面是一个代理的例子:

//定义一个静态方法来实现接口与实现类的直接检验
//静态方法不要写出Interface.prototype ,因为这是写到接口的原型链上的
//我们要把静态的函数直接写到类层次上
//定义一个接口类
var Interface = function (name, methods) {//name:接口名字
  if(arguments.length < 2){
    alert('必须是两个参数')
  }
  this.name = name;
  this.methods = [];//定义一个空数组装载函数名
  for(var i=0; i<methods.length; i++) {
    if(typeof methods[i] != 'string') {
      alert('函数名必须是字符串类型')
    } else {
      this.methods.push(methods[i]);
    }
  }
};
//我们要把静态的函数直接写到类层次上
Interface.ensureImplement = function (object) {
  if (arguments.length < 2) {
    throw  new Error("参数必须不少于2个");
    return false;
  }
  for(var i=0; i<arguments.length; i++){
    var inter = arguments[i];
    //如果是接口就必须是Interface类型
    if(inter.constructor !== Interface) {
      throw new Error("如果是接口类的话,就必须是Interface类型");
    }
    //判断接口中的方法是否全部实现
    //遍历函数集合分析
    for(var j=0; j<inter.methods.length; j++) {
      var method = inter.methods[j];//接口中所有函数
      //object[method]传入的函数
      //最终是判断传入的函数是否与接口中所用函数匹配
      if(!object[method] || typeof object[method] != 'function'){
        //实现类中必须有方法名字与接口中所用方法名相同
        throw new Error('实现类中没有完全实现接口中的所有方法');
      }
    }
  }
}
//图书类
/*
* bid 图书id
* bName 图书名称
* bPrice 图书价格
* */
var Book = function(bid,bName,bPrice) {
  this.bid = bid;
  this.bName = bName;
  this.bPrice = bPrice;
}

//目标类
var myBookShop = (function (){
  var books = {}; // 闭包
  return function (bks) {
    // 初始化
    if (typeof bks === 'object') {
      books = bks;
    }
    //  加书
    this.addBook = function (book) {
      books[book.id] = book;
    }
    // 找书
    this.findBook = function (bid) {
      if(books[bid]) {
        return books[bid];
      }else{
        return null;
      }
    }
    // 还书
    this.returnBook = function (book) {
      this.addBook(book);
    }
    // 借书
    this.lendBook = function (bid) {
      var book = this.findBook(bid);
      return book;
    }
  }
})();
// 步骤三,普通代理

var myBookShopProxy = function (bks) {
  var obj = new myBookShop(bks); // 类似于目标类的引用
  // 加书
  this.addBook = function (book) {
    obj.addBook(book);
  }
  // 找书
  this.findBook = function (bid) {
    return obj.findBook(bid);
  }
  // 还书
  this.returnBook = function (book) {
    obj.returnBook(book);
  }
  // 借书
  this.lendBook = function (bid) {
    return obj.lendBook(bid);
  }
}
//步骤四,添加数据后,开始访问
var proxy = new myBookShopProxy({
  '001': new Book('001', 'extjs', '45'),
  '002': new Book('002', 'js', '60')
});
console.log(proxy.lendBook('001').bName);