当前位置: 首页 > Web前端 > vue.js

不看源码如何学习petite-vue源码

时间:2023-04-01 00:54:51 vue.js

大家好,我是Kason。周末没事做,准备找个代码量小的优秀库学习一下。最后,我选择了最近发布的petite-vue,原因如下:代码量小(仅5.8kb),源代码高度模块化(相比React),易于阅读和基于Vite构建,以及您可以通过执行yarndev开始调试源代码。虚拟DOM和编译时解决方案可以作为阅读Vue源代码的基础。底层的响应式更新原则同样适用于Mobx和SolidJS等库。决定一次阅读多份。但是周末时间那么宝贵,而且我已经4年没有用过Vue了,如何才能高效的学习源码呢?学习源码最好不要看源码。接下来,我将以petite-vue为例,演示学习源码的正确姿势。Petite-vue可以理解为:一个简单的Vue,用真正的DOM替换了Vue模板。例如下面的Demo:add1

{{count}}

div及其后代是真正的DOM标签,所以页面初始化如下:然后执行以下完成petite-vue初始化的代码:createApp({count:0}).mount()此时页面:阅读框架源码,避免一上手就从入口函数一路调试,很容易弄糊涂了。正确的做法是像剥洋葱一样一层层剥:那么,我们先从Performance面板来看第一屏渲染的调用栈:调用栈大致分为两部分:蓝框和红框,先看左边蓝框部分:通过createContext和reactive关键字判断,大概是在创建响应式上下文。至于响应性的含义,我们还不知道。再看右边红框中的部分:从调用栈的深度和页面渲染的效果来看,我们猜测这部分所做的工作包括:遍历DOM完成双向绑定初始化渲染ofdataandviews接下来我们来验证一下猜想。请注意,到目前为止,我们还没有看到一行源代码来验证在遍历DOM调用堆栈中多次调用了walk和walkChildren。大概率是遍历工作执行的具体方法。让我们确认一下。登录源码walk方法:exportconstwalk=(node:Node,ctx:Context):ChildNode|空|void=>{console.log('walk',node);//...}排除换行符"\n"对应的文本节点按以下顺序打印:walkdivwalkwalk"add1"walk

0

walk"0"从打印结果看,这是一次深度优先级遍历(有子节点就遍历子节点,没有子节点就遍历兄弟节点)。显然,petite-vue挂载采用深度优先遍历,对遍历的上下文状态相关的每个DOM节点进行处理。Demo中context包含state{count:0}:createApp({count:0}).mount()

{{count}}

遍历后变为

0

。确定双向绑定的粒度接下来我们需要确认双向绑定的范围,即:触发更新后,会重新遍历多少DOM,以及对应的DOM操作执行?打开Performance后,点击触发更新:可以看到没有walk、walkChildren(或者类似的遍历过程),只调用了reactEffect的一个方法来更新DOM。这意味着挂载时的深度优先遍历在状态和更新DOM的方法之间建立了一对一的对应关系。因为确定了对应关系,所以不需要额外的遍历过程来确定需要改变的DOM。更新状态后,只需要找到更新与其相关的DOM的方法并执行即可。例如:用下面的函数连接count状态:functionsetCount(value){p.textContent=value;}每次count变化时调用setCount(count)来更新p对应的DOM。因此,petite-vue的工作原理主要包括两点:挂载时对DOM的深度优先遍历,statefulDOM的state建立关系和更新DOM的方法(如

{{count}}

)当一对一关系更新时,找到更新状态对应的DOM的方法并执行。可以看到,即使不深入源码,也能对工作流程有一个大概的了解。如果你想更进一步,比如了解关系是如何建立的(涉及到响应式更新),那么你需要深入研究源代码。这里推荐VueMastery的Vue3Reactivity课程,可以补充响应式更新的知识。小结本文介绍了复杂框架源码的阅读方法——从抽象到具体。从mount和update时的调用栈推导出整体工作流程从整体工作流程中发现核心知识——响应式更新掌握了整体工作流程和响应式更新后,阅读自己感兴趣的部分,以免陷入海量的代码。你没用吗?