likes
comments
collection

Vue3.0源码学习——初始化流程分析(3.patch过程)

作者站长头像
站长
· 阅读数 18

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

前言 前文 Vue3.0源码学习——初始化流程分析(2.挂载过程) 了解了Vue挂载的过程,其中会将 vnode 传递给 patch 函数转换为真实dom并挂载在宿主元素上,这篇文章主要讲一下 patch 的过程

什么是patch算法

patch 中文意思是补丁,在Vue中 patch 函数的作用其实就是在渲染的过程中,比较新旧节点的变化,通过打补丁的形式,进行新增、删除、移动或替换的操作

patch 中比较的新旧节点都是 vnode 也就是虚拟dom,避免了大量的dom操作,提升了运行的性能

patch的执行过程

  • 首先挂载函数 mount 中的调用了渲染器函数中的 render 函数

Vue3.0源码学习——初始化流程分析(3.patch过程)

  • 通过打断点单步进入,找到 render patch 都是在渲染函数 baseCreateRenderer 中定义,位置 packages\runtime-core\src\renderer.ts
  • render 中由于挂载的时候传入了第一个参数 vnode 不为空,因此走 else分支 调用了 patch 函数

Vue3.0源码学习——初始化流程分析(3.patch过程)

  • patch 函数真身,首先会对 n2 也就是 新的vnode 的type做一堆switch case操作

Vue3.0源码学习——初始化流程分析(3.patch过程)

  • 第一次传入的是根组件,因此 n2 是一个对象,会进入 processComponent 函数,并调用mountComponent 挂载组件

Vue3.0源码学习——初始化流程分析(3.patch过程)

  • mountComponent 挂载组件,生成组件实例 instance 传入 setupComponent

Vue3.0源码学习——初始化流程分析(3.patch过程)

  • setupComponent 组件初始化,执行到 setupStatefulComponent 函数 Vue3.0源码学习——初始化流程分析(3.patch过程)
  • 最终都会执行 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 传入

Vue3.0源码学习——初始化流程分析(3.patch过程)

  • 生成子树,并继续调用 patch Vue3.0源码学习——初始化流程分析(3.patch过程)

子树 Vue3.0源码学习——初始化流程分析(3.patch过程)

  • 创建真正的dom元素 Vue3.0源码学习——初始化流程分析(3.patch过程)

  • 如果有子节点就递归遍历,重复的 patch Vue3.0源码学习——初始化流程分析(3.patch过程)

能看到这里,相信你基本已经晕了,接下来到调用栈去查看一下patch的过程应该更直观一些

Vue3.0源码学习——初始化流程分析(3.patch过程)

调用栈中查看

Vue3.0源码学习——初始化流程分析(3.patch过程)

Vue3初始化挂载流程图

最后附上流程图更好的理解

Vue3.0源码学习——初始化流程分析(3.patch过程)

往期回顾

Vue3.0源码学习——初始化流程分析(2.挂载过程)

Vue3.0源码学习——初始化流程分析(1.实例创建过程)