Vue.js 3.0源码解析(微课视频版)
上QQ阅读APP看书,第一时间看更新

2.3 effect副作用函数

完成响应式数据介绍后,再次回到createApp()函数内查看后续实现逻辑:

reactive()函数处理完数据后,声明isMount参数,用于判断是否为首次渲染。声明prevTree参数,用于记录当前VNode数据。完成该步骤后,开始执行watchEffect()函数,该函数处理与effect副作用函数相关的内容,此处传入一个存储effect副作用内容的匿名函数,派发更新时,执行该匿名函数,作为当前组件更新的钩子函数。为理解调用关系,此处再次查看notify方法的实现逻辑:

此处遍历subscribers数组获取effect后直接执行调用,完成该操作后整个响应式数据关联就介绍完成。在收集依赖时,将该匿名函数保存在队列内,待派发更新时,再将收集到的依赖进行更新,遍历执行effect副作用函数。继续查看watchEffect()函数的内部实现:

由上述代码可知,当匿名函数传递后,首先会赋值给全局变量activeEffect,然后立刻执行effect副作用函数,完成执行后将activeEffect重新设置为空。设置activeEffect变量临时保存当前副作用函数,实时获取当前上下文,也在触发get或set时判断activeEffect是否有值,避免重复缓存。完成watchEffect()函数的实现逻辑后,查看内部函数实现方法:

watchEffect()函数内部通过call()方法改变this指向,让Component.render函数内this指向state,在render()函数内通过this.count即可访问state内的count,将data数据与render绑定。关于effect副作用函数执行时,mount()和patch()函数的实现,将在2.4节介绍。

此处在createApp执行时,首先执行reactive()函数,该函数实例化Proxy后,将不会往后执行,所以watchEffect会先保存effect副作用函数,并且使用activeEffect全局变量保存当前effect副作用函数后,再执行。在执行effect副作用函数时,会触发reactiveHandlers代理对象。通过这样巧妙的设计,在执行effect副作用函数的过程中,保存当前的effect副作用函数,完成依赖收集的工作。整个代码执行顺序可参考如图2.2所示步骤。

图2.2 执行顺序

该步骤图完整记录了整个createApp内部执行顺序,通过本节内容可以帮助读者理解整个运行流程,以便后续理解整个Vue3的核心功能。