vue3源码分析

1、基于 Proxy 的 reactivity

vue2响应式:

对象:通过defineProperty对对象的已有属性读取和修改进行劫持(监视/拦截)。

数组:通过重写数组原型的七种方法,实现对数组更改的劫持来处理数组响应式。

push、pop、shift、unshift、splice、sort、reverse。

缺点:

对象直接新添加的属性或删除已有属性, 界面不会自动更新;

直接通过下标替换数组元素或更新数组length, 界面不会自动更新;

通过Vue.set()处理实现响应式

对象:Vue.set(this.obj, "name", "chengqiang");

数组:Vue.set(this.list, "0", "chengqiang");

vue3响应式:

通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的增删改查,代理对象中拦截对数据赋值的操作,从而获知数据变化。

通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作。

const dataObj = {};

const dataProxy = new Proxy(dataObj, {
    get(target, key){
        // 收集依赖
        Reflact.get(target, key);
    },
    set(target, key, value){
        // 进行对应界面的更新
        Reflact.set(target, key, value);
    }
});

2、tree-shaking 

Vue 2 的体积其实已经不算大了,但是使用 Vue 3 时可以让打包体积更小。这一方面利益于 Composition API 的设计,另一方面也是因为随着 ESM 模块化规范(和 TS 模块化规范)的成熟,tree-shaking 被使用得越来越广泛了。

tree-shaking 是指针对代码中模块的依赖关系进行静态分析,将完全没有使用到的模块在打包时直接移除掉,只打包使用到的模块,从而减少体积。

得益于 Vue 3 良好的模块划分,开发者在使用 Vue 3 时可以按需选择需要的模块引入,而不用一次性将所有的代码全部引入,这样在打包时 Vue 3 中没有被引用的源码将被移除。

在 Vue 的仓库中专门有一个 @vue/size-check 的包,就是用来测试 tree-shaking 的:

import { h, createApp } from '@vue/runtime-dom'

// The bare minimum code required for rendering something to the screen
createApp({
  render: () => h('div', 'hello world!')
}).mount('#app')

这个例子中只使用了 h 和 createApp,其它的诸如 watch、computed、reactive 等模块都没有被引用,因此打包时也将只包含使用到的源码,从而使整个应用的打包体积变得更小

3、渲染性能优化

vue2 diff算法:

虚拟 DOM 的更新需要对新、旧两棵 VNode 树进行全量遍历和对比,然后才能确定发生变动的地方。

diff 只进行同级比较

  • 如果新节点有子节点而老节点没有子节点,则判断老节点是否有文本内容,如果有就清空老节点的文本内容,然后为其新增子节点。
  • 如果新节点没有子节点而老节点有子节点,则先删除老节点的子节点,然后设置文本内容。
  • 如果新节点没有子节点,老节点也没有子节点,则进行文本的比对,然后设置文本内容。
  • 如果新节点有子节点,老节点也有子节点,则进行新老子节点的比对,然后进行新增、移动、删除的操作。

 根据新老 vnode 子节点不同情况分别处理

 

Vue 3 diff算法性能优化:

以 v-if 和 v-for 作为边界,将模板分成很多 “块”,每个块中的结构是完全固定的,这样块中就不需要进行树的遍历,只需要对比绑定的值即可;

将静态节点、子树等渲染代码移到渲染函数之外,这样可以避免每次渲染时重新创建这些不会变化的对象;

动态数据节点标记(patchflag)节点类型,调用对应节点类型的比较方法,如:文本,属性调用各自的比较方法;

@监听函数的缓存,数据更新,dom事件拿缓存的事件。

将元素的更新类型进行细分,例如动态绑定的部分如果只涉及到 class,则在对比时只需要对比 class 即可,不需要对比它的内容。

4、模版编译

抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

vue2模版解析

vue模版结构:

  <div class="box">
    <h3 class="title">我是一个标题</h3>
  </div>

 抽象语法树:

{
      tag: 'div',
      attrs: [{name: 'class', value: 'box'}],
      type: 1,
      children: [
        {
          tag: 'h3',
          attrs: [{name: 'class', value: 'title'}],
          type: 1,
          children: [
            {text: '我是一个标题', type: 3}
          ],
        }
      ]
    }

vue框架中有一个compile,compile主要负责将模版转化为render函数,而render函数调用后得到虚拟dom树。

编译的过程分两步:

  1. 将模版字符串转化给AST
  2. 将AST转化为render函数

 

 vue3模版解析

  1. 调用 baseParse() 方法,解析传入的模板,生成 AST(即 ast 变量)
  2. 调用 transform() 方法对 AST 进行转换
  3. 调用 generate() 方法,根据转换后的 AST 生成 render() 方法并返回

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值