写点什么

前端 tree 优化实践:渲染速度从 14.65s 到 0.49s

  • 2019-02-15
  • 本文字数:2072 字

    阅读完需:约 7 分钟

前端tree优化实践:渲染速度从14.65s到0.49s

全篇主要思想:递归的本质是栈的读取

先看效果对比

以下都是基于 10000 条子节点数据作对比,先上最终数据对比:


递归版 tree,渲染速度: 14.65s,点击节点处理速度: 9.83s


优化版 tree,渲染速度: 0.49s,点击节点处理速度: 0.18s


递归组件实现 tree:渲染速度 15.71s -1.06s = 14.65s



递归版 tree 性能图-1


递归组件版 tree 点击节点性能分析图:点击节点处理速度: 10.19s - 0.357s = 9.833s ≈ 9.83s



递归 tree 点击节点图-2


最终优化实现 tree: 渲染速度 2.25s - 1.76s = 0.49s



优化 tree 性能图-3


优化版 tree 点击节点性能分析图:点击节点处理速度 0.623s - 0.3s = 0.3s



优化 tree 点击节点图-4


最终对比是:


递归版 tree,渲染速度: 12.19s,点击节点处理速度: 9.52s


优化版 tree,渲染速度: 0.49s,点击节点处理速度: 0.18s

分析问题

我们可以借助 performance 分析一下递归组件的耗时点所在,上递归组件渲染的性能分析:

1.script 耗时分析:


递归 tree script 性能分析图-5


通过图-1 性能瀑布可以清晰的看到 script 执行占了 8.9s 的时间,通过上图即图-5 可以看到 script 的的调用栈主要集中在创建 vue 实例时的 createChildren 上面。

2.render 耗时分析


递归 tree render 性能分析图-6


通过上图即图-6 可以清晰的看到 render 耗时主要集中在 Recalculate Style、Layout 上面。我们知道 Recalculate Style、Layout 主要是样式计算,因此查看代码:



递归组件部分代码图-7


发现在递归的 tree-node 组件里面有很多样式的计算,10000 条子节点就需要计算 10000 次。

3.DOM 结构分析


递归组件 DOM 结构图-8

实现思想

来看我们的开篇思想:递归的本质是栈的读取。


在算法中我们会遇到很多递归实现的案例,所有的递归都可以转换成非递归实现,其中转换的本质是:递归是解析器(引擎)来帮我们做了栈的存取,非递归是手动创建栈来模拟栈的存取过程。


万物都是相通的,递归组件也可以转换成扁平数组来实现:


1.更改 DOM 结构成平级结构,点击节点以及节点的视觉样式通过操作总的 list 数据去实现


2.然后使用虚拟长列表来控制 vue 子组件实例创建的数量。

优化版实现

主要分为两部分功能:


1.tree 数据和 DOM 结构的扁平化;


2.虚拟长列表控制 DOM 渲染数量。

1.tree 数据和 DOM 结构的扁平化


优化版 tree 的 DOM 结构图-9


由上图我们可以看到经过改造之后的 tree 的 DOM 结构,父节点和子节点是平级的,在操作子节点时去操作内存中的 listData 数据来改变相关联节点的状态。


我们再看下 listData 数据的结构:



优化版 tree listData 数据结构图-10


上图即图-10 结合图-9 的 DOM 结构可以对整个功能的实现逻辑一目了然:


listData 中的每一项的 style、checked、path 等信息来描述节点的样式位置和状态,操作一个节点时通过 listData 更改相关节点的状态样式等信息。


因此最终来写我们的代码:



实现.vue 代码图-11


我们再看下 handleCheckChange 的做了什么:



handleCheckChange 处理逻辑图-12

2.虚拟长列表控制 DOM 渲染数量

实现思路:


根节点 DOM 分成两个子节点:fui-tree__phantom 和 fui-tree__content。


两个子节点都是绝对定位,为了在滚动时避免数据的更改回头触发滚动事件。



虚拟列表 DOM 组织结构图-13


根节点解两个子节点 css:


.fui-tree {    height: 400px;    overflow: auto;    position: relative;  }
.fui-tree__phantom { position: absolute; left: 0; top: 0; right: 0; z-index: -1; }
.fui-tree__content { left: 0; right: 0; top: 0; position: absolute; }
复制代码


然后我们通过滚动条的位置来计算我们应该要取哪些数据。


主要代码:



通过 startIndex、endIndex 可以取出我们需要循环的数据列表 renderNodes:


computed: {      renderNodes() {        if (!this.treeNode) return []        return this.treeNode.listData.slice(this.positionConfig.startIndex, this.positionConfig.endIndex)      },      phantomStyle() {        return {          height: this.allListLen * 20 + 'px'        }      }    }
复制代码


结合图-11 的 v-for,这样我们在渲染时的 dom 数量是固定的条数,如下图:



优化版 tree DOM 数量是固定的图-15


虚拟列表的接入可以让即使再多数据量也能渲染固定的 DOM 数量,这样就可以支撑更大数据的渲染和功能。


以上我们实现了业务需求的大数据渲染,目前测试可支撑到 20w 条节点,点击子节点时会有肉眼可见的延迟,主要是图-12 中 handleCheckChange 的数据查找和处理,这块还有一定的优化空间:使用字典树存储节点相关信息,字典树和扁平数组 listData 的每一个元素指向同一个内存地址,在 handleCheckChange 中通过操作字典树来达到操作 listData 的元素的效果,经典的空间换时间的案例。

参考链接


更多内容,请关注前端之巅。



会议推荐


2019 年 6 月,GMTC 全球大前端技术大会 2019 即将到来。小程序、Flutter、移动 AI、工程化、性能优化…大前端的下一站在哪里?点击下图了解更多详情。



2019-02-15 10:228277

评论

发布
暂无评论
发现更多内容

毕业设计

cqyanbo

昆仑分布式数据库独特的变量读写功能介绍

KunlunBase昆仑数据库

数据库 读写分离

TGIP-CN 036 报名|预见 2022 · Apache Pulsar 技术进展与社区动态

Apache Pulsar

开源 架构 云原生 Apache Pulsar 社区

阿里巴巴在开源压测工具 JMeter 上的实践和优化

阿里巴巴云原生

Apache 阿里云 云原生 Jmeter

VuePress 博客优化之增加 Vssue 评论功能

冴羽

JavaScript Vue 前端 vuepress vssues

Linux这5大磁盘分区工具,绝了!

Ethereal

吉利控股集团与百度深化战略合作

百度开发者中心

Hadoop HDFS 3.3.1分布式存储搭建

KunlunBase昆仑数据库

国产数据库

什么是广域网WAN?学WAN,看这篇文章就够了!

Ethereal

一文了解路由平台的 Cisco IOS 和 IOS XE 命名约定,看这篇就够了!

Ethereal

2022年2月云主机性能评测报告

博睿数据

如何基于制品元数据提升交付效率 | 阿里巴巴DevOps实践指南

阿里云云效

云计算 阿里云 云原生 软件开发 持续交付

架构实战营第 4 期 -- 模块九作业

烈火干柴烛灭田边残月

架构实战营

投稿开奖丨轻量应用服务器征文活动(2月)奖励公布

阿里云弹性计算

轻量征文

干货|性能提升密钥,由代码细节带来的极致体验

SphereEx

Apache 数据库 开源 ShardingSphere SphereEx

开发者们看过来~填问卷参与抽奖,双重周边奖励仅限本周!

InfoQ写作社区官方

OpenHarmony 热门活动

Gartner发布服务器虚拟化市场指南 灵雀云作为唯一本土容器厂商入选

York

容器 云原生 数据中心

社区知识库|常见问答 FAQ 集合第 5 期:Broker、Topic、Pulsar 客户端及消息限制等相关问题

Apache Pulsar

开源 架构 云原生 Apache Pulsar 社区

培训第二弹!全国大学生智能汽车竞赛百度竞速组预告

百度开发者中心

建设领先的AI原生云,百度智能云落地新一代高性能AI计算集群

百度开发者中心

如何限制Linux终端中tree命令递归文件列表的深度?

Ethereal

Flutter 设置应用主题色和字体

岛上码农

flutter ios 安卓 移动端 3月月更

架构实战营模块九作业

zhongwy

什么是单臂路由器?如何配置单臂路由?

Ethereal

视频质量评价VMAF,为何让人又喜又忧?

微帧Visionular

视频编码

区块链发展趋势与思考

CECBC

黄金VS比特币:谁更有吸引力?

CECBC

架构实战营 4 期第九模块作业

jialuooooo

架构实战营

模块九作业

李晓笛

架构训练营

业内首家!百度智能云智慧金融业务通过ISO37301合规管理体系认证

百度开发者中心

干货分享 | 推荐两款好用的企业文档管理软件

小炮

前端tree优化实践:渲染速度从14.65s到0.49s_大前端_杨涛峰_InfoQ精选文章