本文试图从原理和源码层面重新理解Vue3的响应式机制,实现对该问题的清晰化阐述,摆脱各种名词和细节的迷雾,从整体上把握这个框架。本文的主体思路参考Vue官方文档: how-reactivity-works-in-vue,不过在文档外进一步通过源码分析进行了验证。为方便大家亲自实践,文章最后附上Vue3源码调试的流程供大家参考。
从MVVM框架的设计初心来看,除了作为框架的VM之外,两侧分别是M和V,M对应的是数据,V对应的是视图,所谓数据驱动就是视图随着数据的变化而更新。进一步扩展,数据可以理解为状态,视图可以扩展为一切回调操作,于是MVVM就可以理解为:当状态变化时自动执行对应的回调操作,这就是响应式的核心。
分析上面那句话,响应式要求两个东西:响应式状态和响应式操作。响应式状态要求能够具备回调操作的绑定和调用功能,而响应式操作则作为被绑定的对象等待执行。
在Vue3当中,响应式状态叫做响应式对象(ReactiveObjects),响应式操作叫做响应式副作用(ReactiveEffect),响应式对象对于操作的绑定叫做跟踪(Track),对于操作的调用叫做触发(Trigger)。
副作用:严格意义上,副作用是相对于纯函数的一个概念。如果一个函数和外界产生了交互,如调用接口、DOM操作、修改全局变量等,该函数就被称作副作用。考虑到实际使用中大部分函数都是副作用,我们可以将所有状态绑定的回调都称作副作用,即状态变化时要做的额外操作。
为什么响应式非要是对象呢?因为JavaScript中只能干预对象属性的读写过程。Vue3利用了JS提供的两种干预方式:对象的getter和setter方法和Proxy代理功能,基于第一种方式,Vue3提供了ref,基于第二种方式,Vue3提供了reactive。
由于副作用(effect)只是一个函数,接下来要讨论的是响应式对象如何在对象属性的读写过程中绑定和触发副作用?
首先全局会有两个变量,一个是activeEffect,指向当前正在执行的effect函数,另一个是effects