Vue3源码学习 -- 3、更新流程分析

整体思路

在探索更新流程之前,我们先大致捋一下更新过程,从而对更新机制有一个整体的认识。

在初始化的过程中,经过了 setupRenderEffect 方法,在这个方法中就建立了更新机制;
当组件中的响应式数据发生变化时会执行更新函数;
在更新函数内部会调用 patch 方法。

接下来就进入源码中详细分析整个更新流程。

更新流程

有了整体思路之后,我们就知道了应该从建立更新机制的 setupRenderEffect 方法看起。
打开 packages\runtime-core\src\renderer.ts ,我们找到了该方法。
在这里插入图片描述
在该函数中,首先声明了 componentUpdateFn 。这个函数就是组件的更新函数,而在首次执行渲染函数时,就已经建立了依赖关系。该函数做了什么,在后面调用时再看,我们接着往下。
在这里插入图片描述
下面又声明了一个 effect 函数,该函数的作用是为数据变化和组件渲染之间建立响应式的联系,使得数据发生变化时调用对应的更新函数更新视图。
effect 是通过 ReactiveEffect 构造的一个实例,传入了3个参数。第一个参数就是上面的更新函数,是更新时真正执行的方法;第二个参数是一个定时器任务,通过 queueJob 对 update 进行处理,将来在更新时就会按照这种方式执行;第三个参数是作用域,我们这里并不关心。
我们看到在 queueJob 中处理的 update 实际上就是 effect.run() 。

接下来我们看一下 queueJob 中做了什么。
在这里插入图片描述
打开 packages\runtime-core\src\scheduler.ts 文件,可以找到 queueJob 方法。该方法就是将任务放入队列,然后执行批量更新,通过 Promise.then() 执行 flushJobs 。也就是说,会在未来微任务队列清空时执行。在这里插入图片描述
flushJobs 会通过循环依次执行任务队列中的更新函数,也就是上面传入的 effect.run() 。
在这里插入图片描述
打开 packages\reactivity\src\effect.ts 文件,我们看到 run 方法返回了当前实例的成员函数 fn()。
在这里插入图片描述
在 run 方法的上面我们看到当前的实例就是通过 ReactiveEffect 构造的,而 fn 就是之前传入的第一个参数,也就是更新函数 componentUpdateFn 。
在这里插入图片描述
我们直接看更新流程,所以直接进入 else 分支。
在这里插入图片描述
可以看到,在更新过程中,先获取了最新的 vnode 和缓存的 oldVnode ,再调用 patch 方法执行 diff 算法,完成更新过程。

单步调试

看完源码,我们在通过单步调试走一遍更新流程。
我们在 packages\vue\examples 目录下新建一个 html 文件,引入打包后的 vue.js ,写一个简单的例子。
在这里插入图片描述
在浏览器中打开文件,在 setInterval 处打上断点,刷新页面,F11进入断点。首先进入了一个只在开发模式中产生作用的 createDevRenderContext 方法,我们并不关心,接着往下进入了 PublicInstanceProxyHandlers 方法中。这个就是当一个值发生变化时,对其 get 和 set 进行拦截,从而进行响应式处理的方法。在这里插入图片描述

由于我们在代码中做的是一次赋值操作,所以会先获取一次 counter 的值,第一次会进入 get 中。接着是赋值,就会进入 set 中。我们将断点打在下面的 set 方法中,进入断点,往下走到407行,这里进行了赋值操作。
在这里插入图片描述
接着F11后,进入了 createSetter 方法,里面返回了一个 set 方法,在一系列操作后,会执行 trigger 方法。

在这里插入图片描述
在 trigger 方法的最后,会执行触发更新的方法 triggerEffects。
在这里插入图片描述
由于当前的值存在 scheduler ,所以这里执行了 scheduler 方法,而没有直接执行更新函数。
在这里插入图片描述
进入 scheduler ,我们发现走到了之前在源码中看到的 effect 方法,而 scheduler 就是其中的第二个参数。
在这里插入图片描述
再往下就是执行 queueJob ,将更新函数加入异步队列,然后执行 queueFlush ,启动批量更新任务。
在这里插入图片描述
根据之前源码部分的分析,我们知道最终执行的更新函数就是 componentUpdateFn ,所以我们将断点打在 componentUpdateFn 的更新流程部分。
在这里插入图片描述
在获取新的 vnode 和 缓存的 oldVnode 之后,就执行了 patch 方法,patch 方法走完后,页面上就渲染出了更新后的内容。

在这里插入图片描述

在这里插入图片描述

总结

整个更新流程可以分为两部分。一个是更新机制的建立,一个是更新过程。

更新机制的建立是在初始化的时候进行的:
结合之前的初始化流程,我们知道在 app.mount 中执行了 setupRenderEffect 方法,在该方法中通过 ReactiveEffect 构造的实例 effect 方法建立了数据变化和组件渲染之间的联系。

更新过程是在响应式数据发生改变时触发的:
在 counter 的值发生变化时,会触发拦截机制,进入 set 方法中;
在 set 中,会将新值赋值给 counter ,然后执行 trigger 方法;
trigger 方法中和更新相关的操作是执行 triggerEffects 方法,该方法会将和 counter 相关的所有 effect 都遍历一遍,并依次执行其中的更新函数;
在调用更新函数之前,会通过调用 effect.scheduler() 的方式来进行更新;
在 scheduler 中会执行 queueJob(update) ,将更新函数加入任务队列;
然后通过 queueFlush 启动批量更新任务;
在 queueFlush 中,会通过 Promise.then() 执行 flushJobs ,也就是在未来微任务队列清空时执行;
flushJobs 中执行的 effect.run() ,就是 effect.fn() ,也就是 ReactiveEffect 中的第一个参数 componentUpdateFn;
在 componentUpdateFn 中,通过 patch 方法执行 diff 算法,完成更新过程。

流程图:

在这里插入图片描述

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值