vue3源码概述

54 阅读4分钟

vue3源码概述

本文选自vue3源码解析第二章

详情见github

本节开始正式进入vue3源码的分析,有了前一节的知识的,我们直接使用demo里面的例子作为用例

源码结构

packages目录下面的包的作用见下表

包目录作用
compiler-core先忽略
compiler-dom先忽略
compiler-sfc先忽略
compiler-ssr先忽略
dts-test直接忽略
reactivity响应式相关代码,比如ref等都在这里
reactivity-transform先忽略
runtime-core渲染的核心代码(于平台无关)
runtime-domdom渲染有关代码
runtime-test直接忽略
server-renderer先忽略
sfc-playground直接忽略
shared公共工具函数
size-check直接忽略
template-explorer直接忽略
vue包导出
vue-compat直接忽略

是不是感觉代码很多,别急,很多包实际上在代码运行的时候是用不到的,比如先忽略的包很多都是编译阶段使用的包在运行阶段是不会起任何作用的,这个以后在说。

核心包

对于非ssr的项目而言,核心的包只有以下四个

包目录作用
reactivity响应式相关代码,比如ref等都在这里
runtime-core渲染的核心代码(于平台无关)
runtime-domdom渲染有关代码
shared公共工具函数

基本数据结构

基本数据结构是在运行中常用的数据结构。

component

常说的组件是import HelloWorld from './helloworld.vue'中的HelloWorld。在使用webpackvue-loader时,这里导入的组件会被vue-loader自动处理。对于Options API的组件来讲,这里以demo中的App.vue来讲,具有以下结构

options-component

对于composite setup的组件来讲,具有一下结构

composite-componet

总结起来就是component是经过编译器处理后得到的产物。具有一定结构

app

一个app是createApp函数的返回值,第一个参数是根组件。第二个参数可选,它是要传递给根组件的 props。根组件就是上面所说的component

app具有以下结构

app

component instance

component instance表示在运行过程中创建好的component,和component的区分是component只是编译后的一个对象,这个对象不需要vue的创建就可以单独存在,而component instancevue在渲染过程中创建的内部对象,用以渲染的用途

component instance具有以下结构

component-instance

vnode

这个不多讲官网文档里面有。vnode是渲染算法的核心结构。type=componentvnode具有以下结构

vnode

vnode还有其他很多种结构这里不列出

container

app.mount函数的第一个参数是container,类型为Element

依赖图

对于type=componentvnode来讲,以上数据结构具有如下的关系

数据结构依赖图转存失败,建议直接上传图片文件

图中的container相关依赖仅为根组件具有,其他component不具有

运行概述

首次渲染

火焰图

record1转存失败,建议直接上传图片文件

从图中可以看出第一次渲染主要分为两步

  1. 创建app对象
  2. 手动调用对象的mount方法

mount函数是第一次渲染的调用的函数,从图中可以看到mount函数会调用render函数,render函数的核心是patch函数。

这里先给出结论,vue的渲染实际上是递归调用patch函数进行深度优先遍历直到完成渲染。

非首次渲染

转存失败,建议直接上传图片文件

转存失败,建议直接上传图片文件

图1左边部分位于图2的红色框区域

从图中可以看到非首次渲染也分为两部分

  1. 触发更新
  2. 执行更新

执行更新的函数调用时处于一个微任务调用栈里面(图2的run MircoTasks)。

之后调用的核心函数是componentUpdateFn,这个函数在之后也会调用patch方法去递归遍历进行渲染

总结

vue3的渲染无论是首次还是非首次核心都是递归调用patch算法进行深度优先遍历进行渲染