大家好,我是卡颂。

周末没啥事,筹备找个优良且代码量不多的库学习下。最终抉择了最近公布的petite-vue,起因如下:

  • 代码量少(只有5.8kb),且源码模块化水平高(相比于React),易读
  • 基于Vite构建,执行yarn dev就能开始调试源码
  • 没有虚构DOM、编译时计划,能够作为读Vue源码的铺垫
  • 底层的响应式更新原理同样实用于MobxSolidJS等库,一次浏览多份播种

就决定是他了。

然而周末工夫这么贵重,而且我都4年没用过Vue了,如何能力高效学习源码呢?

最好是在不看源码的状况下把源码学了

接下来,我以petite-vue为例为大家示范学源码的正确姿态。

怎么快怎么来

能够将petite-vue了解为:用实在DOM取代Vue模版的繁难Vue

比方如下Demo

<script type="module">  import { createApp } from '../src'  createApp({count: 0}).mount()</script><div v-scope>  <button @click="count++">add 1</button>  <p>{{count}}</p></div>  

div及其子孙节点是实在的DOM标签,所以页面初始化时如下:

接着执行如下代码,实现petite-vue初始化:

createApp({count: 0}).mount()

此时页面:

读框架源码切忌一上手就从入口函数一路调试,很容易就懵逼了。正确的形式是像剥洋葱一样一层一层剥开:

所以,让咱们先从Performance面板看看首屏渲染的调用栈:

调用栈大体分为蓝框、红框两局部,先看右边蓝框局部:

通过createContextreactive关键词判断大略是创立响应式上下文。至于响应式的含意,咱们还不分明。

接着看左边红框局部:

从调用栈深度、页面渲染的成果咱们猜想,这部分做的工作包含:

  • 遍历DOM
  • 实现数据与视图的双向绑定
  • 初始化渲染

接下来,咱们来验证猜测。

留神,到目前为止,咱们一行源码都还没看

验证遍历DOM

调用栈中walkwalkChildren被调用屡次,大概率他们就是具体遍历工作执行的办法,让咱们确认下。

在源码walk办法中打上log

export const walk = (node: Node, ctx: Context): ChildNode | null | void => {  console.log('walk', node);  // ...  }

排除换行符"\n "对应的文本节点,打印程序如下:

walk divwalk <button>add 1</button>walk "add 1"walk <p>0</p>walk "0"

从打印后果看,这是个深度优先遍历(如果有子节点就遍历子节点,没有子节点就遍历兄弟节点)

显然,petite-vue mount时采纳深度优先遍历,并对遍历到的每个与上下文状态相干的DOM节点进行解决。

Demo中,上下文蕴含状态{count: 0}

createApp({count: 0}).mount()

在遍历后<p>{{count}}</p>变为<p>0</p>

确定双向绑定的粒度

接下来咱们须要确认双向绑定的作用范畴,即:

触发更新后,多大范畴的DOM会被从新遍历并执行相应DOM操作?

关上Performance后,点击<button>add 1</button>触发更新:

能够看到,没有任何walkwalkChildren(或相似遍历过程),只调用了reactiveEffect一个办法就更新了DOM

这意味着mount时的深度优先遍历建设了状态更新DOM的办法之间一一对应的关系。

因为对应关系确定了,就不再须要额定的遍历过程确定须要变动的DOM

当更新状态后,只须要找到与他有关系的更新DOM的办法执行就行。

比方:将count状态与如下函数建立联系:

function setCount(value) {  p.textContent = value;}

每当count变动后调用setCount(count)就能更新p对应DOM

所以,petite-vue的工作原理,次要包含两点:

  1. mount时深度优先遍历DOM,对有状态的DOM(比方<p>{{count}}</p>)建设状态更新DOM的办法之间一一对应的关系
  2. update时找到该状态对应的更新DOM的办法并执行

能够看到,即便不深刻源码,也能大体理解工作流程。

如果你想更进一步,比方理解关系是如何建设的(波及到响应式更新),那么就须要深刻源码了。

这里举荐Vue MasteryVue 3 Reactivity课程,能够补齐响应式更新这块常识。

总结

本文介绍了简单框架源码的浏览方法 —— 即从形象到具体。

  1. mount时与update时的调用栈推导出整体工作流程
  2. 整体工作流程中发现外围常识 —— 响应式更新

当把握整体工作流程响应式更新后,再浏览本人感兴趣的局部才不至于陷入宏大的代码量中。

你,学废了么?