Vue3执行流程思路分析-流程图
了解vue3大致执行原理,从创建到渲染
一. 前言
本文只在为大家梳理完整的vue3
代码执行流程,从创建createApp
到渲染为真实dom
节点。在读后续文章时,请大家参考以下流程图食用,好了废话不多说,开整!!!(本文主要为梳理思路,不展示太多源码,想了解细节可以看我的其他文章,谢谢!!!
)
点击放大图片->
[c430f20c3e2c4d278cc1cedbfdb95c5f~tplv-k3u1fbpfcp-watermark.image (1221×722) (byteimg.com)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jN0tTAdt-1656666680613)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c430f20c3e2c4d278cc1cedbfdb95c5f~tplv-k3u1fbpfcp-watermark.image?)]
二. Vue3 思路分析
提示:一定要按照流程图哦!!!
1. createRender(options)
我们创建vue3
时,最常见的一个api
就是createApp
,但是在执行createRender
时,createApp
还没有被创建,那该方法是干什么的呢,传入的参数有是什么呢?我们接着往下看。
options
:源码中也叫做nodeOps
,其实就是vue3
自己重新封装的一些dom
操作,例如insert、remove、createElement等
,在pc端,其实就是利用domcument
下的一些原生方法实现
优点:
那就有人要问了,为什么要重新封装,首先有这么几点好处:
- 封装后使用更清楚简短,方便调用
- 最重要的一点,那就是将
vue
的渲染工作与dom
操作完全解耦,这样更适合多端操作,只需要重入对应的nodeOps
即可,自己重新封装对应的dom
操作方法,比如移动端等
从流程图来看,调用该方法之后,返回三个Api
,其中我们只关心两个重要的也是常用的createApp、render
我们继续往下看。
2. createApp
这个方法大家应该都不陌生,该方法传入一个根组件rootComponent
,但是并没有做任何处理,在该方法中主要任务创建了一个全局对象app
。我们来看下app中常见的几个api
:
App
- use: 用来注册插件,为
vue
实现扩展,如vueRouter、vuex、pinia等
- component: 用来注册全局组件,可以在任意组件中使用
注意:以上方法都应该在mount挂载之前执行
- mount: 这一步也就是最关键的一部,开始执行将组件渲染的第一步,我们继续往下看
3. app.mount(‘#app’)
从流程图中我们可以看到,挂载中主要执行了两个操作
createVNode
首先将我们传入的根组件传入到createVNode
方法中,将组件包装成vnode
对象并且返回render(vnode, rootContainer)
此处的render
就是在前边执行createRender
时返回的方法,我们在此处继续执行它,并且传入两个参数,第一个是我们包装后的rootComponent
,第二个是挂载传入真实domrootContainer
好了,mount
执行完毕,我们进入到render
中继续向下执行
4. render(vnode, container)
在此方法中,做了一个最重要的工作就是将已经渲染的vnode
,也可以称之为旧的vnode
保存到container._vnode
上,然后调用
patch(container._vnode|| null, vnode)
这样,就形成了新旧vnode
,也就有了diff
的说法,让我们进入到patch
方法中。
5. patch(n1, n2, container)
patch
中文意思打补丁,也就描述了他的用法,对比新旧vnode
,也就是我们常说的diff
算法,将新的vnode
渲染到真实dom中。
该方法中主要分为了两大分支,当然还有其它,我们就先忽略,跟着主线走下去
-
processComponent
当传入的n2为组件时进入这个分支 -
processElement
当传入的n2为元素类型时走该分支
我们先进入processComponent
来对传入的rootComponent
进行处理
6. processComponent
该方法中又出现了两个分支
- mountComponent: 在第一次挂载时执行
- updateComponent: 组件跟新时执行
我们接着往下看
7. mountComponent
该组件中执行了三个主要的方法,我们一个个来看
- createInstance
首先是创建实例,我们自定义的每个组件第一次渲染时都会走该分支,为每个组件定义了一个组件实例instance
,因此vue3
中就有了一个方法getCurrentInstance
来访问每个组件的实例。 - setupComponent
这一步非常重要,该方法接受一个参数,也就是刚刚创建的组件实例,在这一步中,调用了我们传入的setup
,所以,我们调用的所有方法,也就是在这被执行,比如reactive,ref,生命hook,watch,computed等
,之后将setup
调用的结果保存到instance
中的setupState
属性中。 - setupRenderEffect
在一切准备工作都做完之后,接下来就该进行渲染,我们继续进入到该方法中。
8. setupRenderEffect
该方法中创建了一个componentUpdateFn
组件更新函数,也就是在这,实现了真正的响应式处理,在setupComponent
中,执行了setup
,在这我们对数据进行了响应式处理,利用reactive/refs
对数据实现了处理,在get
中收集依赖,set
中更新依赖。
在创建好componentUpdateFn
方法之后,我们创建了一个新的对象
new ReactiveEffect(componentUpdateFn)
,之后我们执行返回对象的run
方法,其中执行了传入的componentUpdateFn
函数,在componentUpdateFn
中,我们首先对组件的render
或者template
进行处理,也就对我们用到了响应式数据进行了get
,由此,将ReactiveEffect
收集到对应数据的依赖中,在每次数据修改时,执行componentUpdateFn
,之后,在挂载函数中继续执行patch
,传入处理后的render
或者temeplate
,至此回到patch
中,进行递归。
9. patch
此时,传入的是根标签包装后的vnode
,所以,此次走的分支为processElement
,让我们跟着流程图继续往下看。
10. processElement
- mountElement
在该方法中,我们利用我们传入的nodeOpts
,也就是dom操作方法,将vnode
渲染为真实的dom,此时,终于将组件渲染到页面上,同时将转换的真实dom存放在vnode.el
上。 - patchElement
该方法也就是diff
算法的核心,当组件更新之后,通过diff
算法,将新的vnode
渲染到页面上。
三. 结尾
至此,vue3从创建到渲染的所有流程执行结束,在数据更新之后,我们通过执行依赖,也就是componentUpdateFn
函数,重复之前的步骤,重新执行组件的render函数
获取根标签,传递给patch
,然后更新页面,一直重复该过程。也就实现了页面的改变。直到网页关闭。
更多推荐
所有评论(0)