热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue3diff第二篇:从源码看性能优化

前提:在第一篇vue3diff第一篇:diff算法代码解析我们进行了diff核心算法解析,会引发一些思考。太长不看版:1.新增在同级节点非尾部位置新增或删除

前提:在第一篇vue3 diff第一篇:diff算法代码解析我们进行了diff核心算法解析,会引发一些思考。

太长不看版:
1. 新增在同级节点非尾部位置新增或删除,都会导致新增位置以及后面的全部节点无法复用 (并不仅仅指v-for出来没key的)
2. vue3 相对于vue2 性能优化点除了lis(最长递增子序列)实现最小化移动以外,只diff动态节点是一个很大的优化点
(flutter里也有类似优化,const声明静态节点)

2021-6-18新增
这两天研究react发现在文档中有对思考一这种现象具体的场景描述,react协调

思考一、由于是同级比较,块状节点变成vdom后也有children(不管是不是v-for循环出来的),在vue3会进入patchUnkeyedChildren,那在页面新增或删除,会导致整个页面dom都会重建??

// 这是楼层板块

测试

测试

测试 ...
// 这是新闻板块
测试 测试 ...
针对以上结构我们新增一个header板块

测试

测试

...
// 这是楼层板块

测试

测试

测试 ...
// 这是新闻板块
测试 测试 ...

以上结构,如果说在末尾,也就是新闻板块下面新增footer板块,patch没问题,一一对应然后patchchildren,里面的child还能复用
但是,如果在顶部新增header板块,这就行不通了。我们再看patch代码

 patchUnkeyedChildren方法简要代码

 const patchChildren: PatchChildrenFn = (n1, n2,...) => {
    const { patchFlag, shapeFlag } = n2
     if (patchFlag & PatchFlags.KEYED_FRAGMENT) {
          patchKeyedChildren(){}
     } else if (patchFlag & PatchFlags.UNKEYED_FRAGMENT) {
     1. 遍历新旧中最短的节点,依次patch,如果不是相同节点,直接卸载

       const commOnLength= Math.min(c1.length, c2.length)
             for (let i = 0; i  c2.length? unmountChildren(c1,...,commonLength) : mountChildren(c2,...,commonLength)

}
}

很明显 patch(c1[i],c2[i]) ,新节点header和旧节点floor比较,虽然能复用,但是子节点就完全不同了。

实际场景:v-if渲染,或者拖拽,删除
结论:新增在同级节点非尾部位置新增或删除,都会导致新增位置以及后面的全部节点无法复用,vue2的双端比较大体也是如此

所以:key的重要性就不必说了
并且尽量不要跨层级的修改dom
在开发组件时,保持稳定的 DOM 结构会有助于性能的提升

思考二、在页面上很多元素都是静态不变的,这种也会参与diff吗?

这是vue3相对vue2做的优化,使用patch flag 优化静态树,只diff会变化的数据
vue3版template 转为render函数在线查看点我,该地址在线将template转为render函数,再由下图中的_createVNode,_createBlock转为vdom

vue3 diff第二篇:从源码看性能优化
企业微信截图_16233921121799.png

vue2版template转为render函数在线查看点我

vue3 diff第二篇:从源码看性能优化
企业微信截图_16233915971830.png

从上面可以发现,vue3使用_createBlock创建了一个fragment包裹了动态节点,并且在末尾还根据节点动态值不同分为STABLE_FRAGMENT, TEXT。如果仅仅是动态属性,就只标记了属性PROPS。具体还有事件的缓存,可以在在线地址中点击options仔细查看区别

这里是源码createBlock部分,实际上也是调用了createVNode生成节点
export function createBlock(
  type: VNodeTypes | ClassComponent,
  props?: Record | null,
  children?: any,
  patchFlag?: number,
  dynamicProps?: string[]
): VNode {
  const vnode = createVNode(
    type,
    props,
    children,
    patchFlag,
    dynamicProps,
    true /* isBlock: prevent a block from tracking itself */
  )
  // save current block children on the block vnode
  vnode.dynamicChildren =
    isBlockTreeEnabled > 0 ? currentBlock || (EMPTY_ARR as any) : null
  // close block
  closeBlock()
  // a block is always going to be patched, so track it as a child of its
  // parent block
  if (isBlockTreeEnabled > 0 && currentBlock) {
    currentBlock.push(vnode)
  }
  return vnode
}

我们再看上面提到的patchUnkeyedChildren方法,里面都用到了判断,证明只有这些标记的才会参与到diff比较,静态的不会比较

 if (patchFlag & PatchFlags.KEYED_FRAGMENT) {
          patchKeyedChildren(){}
     } else if (patchFlag & PatchFlags.UNKEYED_FRAGMENT) {
        patchUnkeyedChildren()
}

patchflags具体有哪些标志,点我看源码

/**
 *
 * Patch flags can be combined using the | bitwise operator and can be checked
 * using the & operator, e.g.
 *
 * ```js
 * const flag = TEXT | CLASS
 * if (flag & TEXT) { ... }
 * ```
 */
export const enum PatchFlags {
  TEXT = 1,
  CLASS = 1 

上面Flag都是使用

1 

再看源码中判断

patchFlag & PatchFlags.KEYED_FRAGMENT

KEYED_FRAGMENT = 1 

推荐阅读
  • vue使用
    关键词: ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • C++中的三角函数计算及其应用
    本文介绍了C++中的三角函数的计算方法和应用,包括计算余弦、正弦、正切值以及反三角函数求对应的弧度制角度的示例代码。代码中使用了C++的数学库和命名空间,通过赋值和输出语句实现了三角函数的计算和结果显示。通过学习本文,读者可以了解到C++中三角函数的基本用法和应用场景。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Todayatworksomeonetriedtoconvincemethat:今天在工作中有人试图说服我:{$obj->getTableInfo()}isfine ... [详细]
  • 2016 linux发行版排行_灵越7590 安装 linux (manjarognome)
    RT之前做了一次灵越7590黑苹果炒作业的文章,希望能够分享给更多不想折腾的人。kawauso:教你如何给灵越7590黑苹果抄作业​zhuanlan.z ... [详细]
  • 手把手教你使用GraphPad Prism和Excel绘制回归分析结果的森林图
    本文介绍了使用GraphPad Prism和Excel绘制回归分析结果的森林图的方法。通过展示森林图,可以更加直观地将回归分析结果可视化。GraphPad Prism是一款专门为医学专业人士设计的绘图软件,同时也兼顾统计分析的功能,操作便捷,可以帮助科研人员轻松绘制出高质量的专业图形。文章以一篇发表在JACC杂志上的研究为例,利用其中的多因素回归分析结果来绘制森林图。通过本文的指导,读者可以学会如何使用GraphPad Prism和Excel绘制回归分析结果的森林图。 ... [详细]
author-avatar
Dearlily2046_394
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有