Vue3.0源码学习——初始化流程分析(3.patch过程)
「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
前言 前文 Vue3.0源码学习——初始化流程分析(2.挂载过程) 了解了Vue挂载的过程,其中会将
vnode
传递给patch
函数转换为真实dom并挂载在宿主元素上,这篇文章主要讲一下patch
的过程
什么是patch算法
patch 中文意思是补丁,在Vue中 patch
函数的作用其实就是在渲染的过程中,比较新旧节点的变化,通过打补丁的形式,进行新增、删除、移动或替换的操作
patch
中比较的新旧节点都是 vnode
也就是虚拟dom,避免了大量的dom操作,提升了运行的性能
patch的执行过程
- 首先挂载函数
mount
中的调用了渲染器函数中的render
函数
- 通过打断点单步进入,找到
render
patch
都是在渲染函数baseCreateRenderer
中定义,位置packages\runtime-core\src\renderer.ts
- 在
render
中由于挂载的时候传入了第一个参数vnode
不为空,因此走else分支
调用了patch
函数
patch
函数真身,首先会对n2
也就是新的vnode
的type做一堆switch case操作
- 第一次传入的是根组件,因此
n2
是一个对象,会进入processComponent
函数,并调用mountComponent
挂载组件
mountComponent
挂载组件,生成组件实例instance
传入setupComponent
setupComponent
组件初始化,执行到setupStatefulComponent
函数- 最终都会执行
finishComponentSetup
完成组件初始化
这个例子没有自己编写
render
,其中就会执行一些列编译操作,然后回生成一个render
最终添加到组件实例上,还对Vue2.0做了兼容
export function finishComponentSetup(
instance: ComponentInternalInstance,
isSSR: boolean,
skipOptions?: boolean
) {
const Component = instance.type as ComponentOptions
...
// template / render function normalization
// could be already set when returned from setup()
if (!instance.render) {
// only do on-the-fly compile if not in SSR - SSR on-the-fly compilation
// is done by server-renderer
// 没有手动添加 render
if (!isSSR && compile && !Component.render) {
...
}
instance.render = (Component.render || NOOP) as InternalRenderFunction
// for runtime-compiled render functions using `with` blocks, the render
// proxy used needs a different `has` handler which is more performant and
// also only allows a whitelist of globals to fallthrough.
if (installWithProxy) {
installWithProxy(instance)
}
}
// support for 2.x options 兼容vue2.0
if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
...
}
// warn missing template/render
// the runtime compilation of template in SSR is done by server-render
if (__DEV__ && !Component.render && instance.render === NOOP && !isSSR) {
...
}
}
- 回到
mountComponent
,执行到setupRenderEffect
副作用安装,这里会将之前的instance
传入
- 生成子树,并继续调用
patch
子树
-
创建真正的dom元素
-
如果有子节点就递归遍历,重复的
patch
能看到这里,相信你基本已经晕了,接下来到调用栈去查看一下patch的过程应该更直观一些
调用栈中查看
Vue3初始化挂载流程图
最后附上流程图更好的理解
往期回顾
转载自:https://juejin.cn/post/7056081078607413284