LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

Vue响应式机制深度解析:你真的掌握了吗?

admin
2025年2月18日 21:22 本文热度 186

作者:啥也不会的码农

https://juejin.cn/post/7465330375663386650


背景

vue3最新版本目前已更新至3.5了,很多同学经过这几年的使用,相信对vue3的常用api都已经烂熟于心了。

但每每被问到源码时,还是虽表面强装镇定,实则内心慌的一批。。。就比如我们经常使用的reactive,很多同学最后就只会憋出一句:reactive的原理是proxy,然后……,就没有然后了

今天我就带着大家将reactive方法一撸到底。

总览

话不多说,直接上图,接下来将带着大家跟着这张图结合源码搞懂reactive的核心源码。


reactive

上面这张图分为上中下三部分,我们一部分一部分进行拆解,首先是最上面部分,这其实就是reactive函数的核心代码

 

假如我们有一个如下的example.js文件:

<script setup>
import { reactive,effect } from 'vue'
const obj = reactive({
   name: '法外狂徒张三'
})
effect(() => {
    document.getElementById('app').innerText = obj.name
})
</script>

当我们写下这段代码的时候,实际上是调用了vue中的reactive函数。我们可以在vue源码的packages\reactivity\src\reactive.ts中找到reactive函的实现:

可以看到reactive函数的实现非常简单,就仅仅返回了一个createReactiveObject方法执行后的结果。

我们看到,createReactiveObject函数最终是会执行new Proxy生成一个proxy实例,如果不了解Proxy的同学可以自行去MDN[1]中学习,然后将这个proxy代理对象和target以键值对的方式建立联系,后续当同一个target对象再次执行reactive函数时,直接从proxyMap中获取,最终返回这个proxy代理对象。

所以,整个reactive函数确实只完成了一件事,那就是生成并返回proxy代理对象,这也是大多数同学探索vue实现响应式原理的终止点。

baseHandlers

reactive函数生成的对象之所以能够实现响应式,是因为Proxy劫持了target对象的读取和写入操作,即Proxy的第二个参数:baseHandlers。 接下来,进入中间部分:

我们看看vue源码对baseHandlers的实现,进入packages\reactivity\src\baseHandlers.ts中我们可以看到以下代码(不重要的代码都被我删除了):

createReactiveObject函数的参数,我们可以知道,Proxy构造函数中的第二个参数其实是MutableReactiveHandler实例,而MutableReactiveHandler继承了BaseReactiveHandler,因此该实例对象中会包含着一个getset函数,这也是vue完成响应式原理的核心部分。


get函数中,除了返回一个`Reflect.get`[2]的结果,还调用了一个track函数,track函数的实现在packages\reactivity\src\dep.ts中:


track函数的作用是收集依赖。它最终会构造一个类型为WeakMap[3]targetMap,其键是我们传入的那个target对象,值是一个Map[4]类型的depsMapdepsMap中存放的才是target对象keydep的对应关系。而dep中存放的就是收集到的依赖。这么说起来有点绕,直接上图:


而在set中的trigger函数执行时,所有存储在dep中的依赖都会被挨个调用。

effect

我们可以看到,dep中的依赖是一个个的ReactiveEffect实例,而这个实例又是从何而来呢?这就要靠我们的effect函数了。

effect函数需要传递一个函数作为参数,这个函数被称之为副作用函数

effect函数中,会调用一个ReactiveEffect构造函数生成ReactiveEffect实例,这个实例会作为依赖被收集。实例中有一个run方法,并且在run方法执行时会调用effect函数传入的参数,即,副作用函数。从而触发proxy代理对象中的get行为,将这个ReactiveEffect实例作为依赖收集到dep

总结

最后总结一下reactive函数的执行流程:首先,当我们调用reactive函数并传入一个target对象时,reactive内部会调用createReactiveObject函数生成并返回一个proxy代理对象。这个proxy代理对象中get方法会收集并以键值对的方式存储依赖,当改变对象的某个属性时,触发proxy的set函数,set函数中的trigger函数会从之前存储的对象中循环调用所有依赖。


阅读原文:原文链接


该文章在 2025/2/19 13:10:29 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved