• Vue 3.0 性能提升主要是通过哪几个方面体现的?


    一. 响应式系统升级

    1. Vue.js 2.x 中响应式系统的核心是 Object.definePropertry

    2. Vue.js 3.x 中使用 Proxy 对象重写响应式系统

    • 可以一次性监听所有属性
    • 可以监听动态新增的属性
    • 可以监听删除的属性
    • 可以监听数组的索引和length属性 

    详细解释:

    Object.defineProperty Vs Proxy

    1. Object.defineProperty 无法一次性监听所有属性, Proxy 可以

    const personInfo = {
      name: 'zhangsan',
      age: 18,
      sex: '男'
    }
    const proxy = new Proxy(personInfo, {
      get(target, key) { },
      set(target, key, newValue) { }
    })
    
    Object.keys(personInfo).forEach(key => {
      Object.defineProperty(personInfo, key, {
        set() { },
        get() { }
      })
    })
    

      

    2. Object.defineProperty 无法监听动态新增的属性, Proxy 可以

    const personInfo = {
      name: 'zhangsan',
      age: 18,
      sex: '男'
    }
    
    const proxy = new Proxy(personInfo, {
      get(target, key) {
        console.log('get', key)
      },
      set(target, key, newValue) {
        target[key] = newValue
        return true
      }
    })
    Object.keys(personInfo).forEach(key => {
      Object.defineProperty(personInfo, key, {
        set() { },
        get() { }
      })
    })

    personInfo.from = '上海'

    console.log(proxy) // Proxy 生效 Object.defineProperty 不生效

      

    3. 可以监听删除的属性?

    const personInfo = {
      name: 'zhangsan',
      age: 18,
      sex: '男'
    }
    
    const proxy = new Proxy(personInfo, {
      get(target, key) {
        console.log('get', key)
      },
      set(target, key, newValue) {
        target[key] = newValue
        return true
      }
    })
    
    Object.keys(personInfo).forEach(key => {
      Object.defineProperty(personInfo, key, {
        set() { },
        get() { }
      })
    })
    
    delete personInfo.age
    console.log(personInfo) // proxy 生效 Object.defineProperty不生效
    

     

    4. 可以监听数组的索引和length属性 

    const personInfo = [1, 2, 3, 4]
    
    const proxy = new Proxy(personInfo, {
      get(target, key) {
        console.log('get', key)
        return key in target ? target[key] : undefined
      },
      set(target, key, newValue) {
        target[key] = newValue
        return true
      }
    })
    
    personInfo.forEach((item, index) => {
      Object.defineProperty(personInfo, index, {
        set() { },
        get() { }
      })
    })
    
    
    personInfo[0] = 8 // 都生效
    personInfo[5] = 6 // proxy 生效
    personInfo.push(99) // proxy 生效
    

      

    二. 编译优化

    1. Vue.js 2.x 通过标记静态节点,优化 diff 的过程

    2. Vue.js 3.x 通过标记和提升所有的静态根节点,diff 的时候只需要对比动态节点内容

    • Fragments ( 升级 Vetur 插件 )
    • 静态提升
    • Patch flag
    • 缓冲事件处理函数

    详细解释:

    此处我们用到线上编译器来查看 vue 2.xvue3.x 的编译区别~

    1. 首先看一下,当文件内部,不包含任何内容时,Vue2.x 编译是空的,Vue 3.x 编译内部包含 render 函数,返回为null

    2. 我们先放入一个 Dom, 可以看到 vue2.x 和 vue 3.x 编译的部分完完全全重构了,之前 Vue2.x 采用,_c 的模式创建标签,_v 为 Vnode 节点, 而当前的 Vue 3.x 通过 _createBlock 生成 block tree 

    - Vue 2.x 数据更新并触发重新渲染的粒度是组件级的,单个组件内部需要遍历该组件的整个 vnode 树

    - Vue.js 3.0 做到了通过编译阶段对静态模板的分析,编译生成了 Block tree。Block tree 是一个将模版基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的。每个区块只需要追踪自身包含的动态节点。

    3. 新引入Fragments(片段)特性:Vue 3.x 模板中不需要再创建一个唯一的根节点,模板里可以直接放文本内容或者很多同级的标签, Vue2.x 需要唯一的节点

    4.  静态提升:静态节点都会被提升到render 的外部,只有初始化时会被创建,再次调用render时不会再次创建,可以直接重用这些静态节点对应的vnode

    5. Patch flag

    6. 缓存事件处理函数减少了不必要的更新操作

    三. 源码体积的优化

    1. Vue.js 3.x 移除了一些不常用的API

    • 例如:inline-template, filter 等

    2. Tree-shaking

    详细解释:移除一些不常用的API这里我们很好解释,在这里我们就重点讲一下 Tree-shaking, Tree-shaking就是把无用的模块进行“剪枝”,很多没有用到的API就不会打包到最后的包里。

    tree-shaking的原理是: 依赖 ES2015 模块语法的静态结构(即 import 和 export),通过编译阶段的静态分析,找到没有引入的模块并打上标记。

    举例说明一下:

    1. import 的引用

    // src/assets/index.js
    
    export function testA() {
      console.log('A')
    }
    
    export function testB() {
      console.log('B')
    }
    
    // src/assets/data.json
    
    {
      "name": "colin",
      "gender": "male"
    }
    
    // src/main.js
    
    import { createApp } from 'vue'
    import App from './App.vue'
    
    // 测试代码开始
    import { testA } from './assets/js/index'
    import { name } from './assets/data.json'
    
    console.log(name)
    
    // 测试代码结束
    
    createApp(App).mount('#app')
    

     

    以上代码,我们将 testA 方法引用,但未使用,data.json 引用,同时使用后,npm run build 打包,我们会发现,data.json 文件

    内容已被打印,但testA 在打包后的文件内,没有发现被引用的情况

    修改 main.js

    import { createApp } from 'vue'
    import App from './App.vue'
    
    // 测试代码开始
    
    import { testA } from './assets/js/index'
    import { name } from './assets/data.json'
    
    console.log(testA())
    console.log(name)
    
    // 测试代码结束
    
    createApp(App).mount('#app')
    

    进行再次打包,我们会看到 testA 已经被成功的打印,但在打包的js中,我们并没有找到 testB 方法,并且也没有找到  assets/data.json 下的  gender 字段,所以此处我们的按需加载已经完成了,但这只是Tree-sharking的一部分

    2. require 引用

    修改 main.js 文件

    import { createApp } from 'vue'
    import App from './App.vue'
    
    // 测试代码开始
    
    const test = require('./assets/js/index')
    
    // 测试代码结束
    
    createApp(App).mount('#app')
    

      

    打包后,我们会发现 我们通过 require 引用的文件,即使未使用,但还是打包在压缩包内

    从这上面一点,我们发现,Tree-sharking 只支持 import 或者 export 的形式,也就是 依赖ES6 内部的静态分析

    所谓静态分析就是不执行代码,从字面量上对代码进行分析,ES6之前的模块化,比如我们可以动态require一个模块,只有执行后才知道引用的什么模块,这个就不能通过静态分析去做优化。

    这是 ES6 modules 在设计时的一个重要考量,也是为什么没有直接采用 CommonJS,正是基于这个基础上,才使得 tree-shaking 成为可能,这也是为什么 rollup 和 webpack 2 都要用 ES6 module syntax 才能 tree-shaking。

  • 相关阅读:
    echarts 折线图(移动端)X轴显示不全
    文字超出省略号类型
    逻辑运算为true
    13年省赛总结
    PyCharm专业版破解教程
    django之定义统一返回数据格式与GET/POST装饰器
    Xmind8破解教程
    django之mysqlclient安装
    django之“static”全局设置
    django之集成第三方支付平台PaysAPI与百度云视频点播服务接入
  • 原文地址:https://www.cnblogs.com/gqx-html/p/14543564.html
Copyright © 2020-2023  润新知