Vue3的编译优化:Block树和PatchFlags

本文探讨Vue3中的编译优化,包括Blocks和PatchFlags的概念。Block能提取动态VNode,减少不必要的DOM比较,提高性能。PatchFlags属性用于标记动态内容,简化更新流程。文章详细解释了Block的动态节点收集、block嵌套以及面临结构变化时的处理策略,同时也提及了v-for和v-if指令如何作为Block处理。最后,提到了静态提升(hoist)优化,避免了静态内容的重复创建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注:本文只是介绍实现原理,并非常规源码解读

众所周知,Vue中的tamplate会被编译为渲染函数,渲染函数执行生成DOM子树,然后根据组件实例的状态执行mount或patch,如果patch,diff算法会对比两颗子树并进行更新。

观察这段模板:

<div>
  <div>HelloVue!</div>
  <p>{
  { text }}</p>
</div> 

这段模板对应的虚拟DOM如下:

{
  tag:'div',
  children:[
  {tag:'div',children:'HelloVue'},
  {tag:'p,children: _context.text}
  ]
} 

传统diff算法对比DOM树更新流程:

1.对比外层div,它的props,和它的子节点,
2.对比内层div,它的props,和它的文本子节点
3.对比内层p,它的props,和它的文本子节点, 

可以看到diff算法做了很多没啥意义的对比,这段代码其实只有text绑定了渲染上下文中的内容,其余内容都是静态内容,所以虚拟DOM只需要对比p标签的文本节点就可以完成内容更新,从而提升性能。但是从上面的虚拟DOM可以看到,运行时其实没办法知道哪个文本节点是动态节点,children数组只是两个普通的vnode

Blocks和patchFags

还是相同的一段模板:

<div>
  <div>HelloVue!</div>
  <p>{
  { text }}</p>
</div> 

我们很容易就能看出来只有p标签含有动态内容,Vue3的模板经过编译后,可以把从模板中提取到这个信息附着到对应的vnode上,可以看到编译后的vnode中p标签多了一个patchFlag属性。

{
  tag:'div',
  children:[
  {tag:'div',children:'HelloVue'},
  //patchFlag等于1说明这个节点的textContent是动态内容
  {tag:'p,children: _context.text,patchFlag: 1 } 
  ]
} 

patchFlag属性可以让运行时知道这个vnode是一个含有动态内容的vnode(后面简称动态vnode),而且根据这个属性的值还可以精准的判断标签的动态部分到底在哪。所以可以在创建VNode的时候,把Vnode子节点中的被patchFlag标记的动态vnode提取出来(这个提取过程后面会讲到),保存在它自己的dynamicChildren数组内。我们把含有这个dynamicChildren数组的VNode就叫做一个block,block不只会提取到children的动态VNode,还可以提取到所有子代动态VNode。

当然vnode也并不是凭空产生的,而是由render函数产生,但是render函数不会直接返回vnode,要通过辅助函数createVNode()

createVNode的实现大概如下:

 function createVNode(tag,prop
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值