logo

S2

  • 使用文档
  • API 文档
  • 图表示例
  • 在线体验
  • 更新日志
  • 所有产品antv logo arrow
  • 2.x
  • 简介
  • 快速上手
  • 基础教程
    • 基本概念
      Updated
    • 表形态
      • 透视表
        Updated
      • 明细表
        Updated
    • 字段标记
      Updated
    • 小计总计
    • 排序
      • 基础排序
        Updated
      • 组内排序
        Updated
    • 主题配置
      Updated
    • Tooltip
      Updated
    • 数据格式化
      New
    • 多行文本
      New
    • 国际化
    • 分页
      New
  • 进阶教程
    • 单元格渲染类型
      • 链接
      • 图片
        New
      • 视频
        New
      • 迷你图表
      • 结合@antv/g2
      • 自定义渲染
    • 自定义
      • 自定义 Hook
        Updated
      • 自定义行列头分组
        New
      • 自定义 Icon
        Updated
      • 自定义单元格对齐方式
        Updated
      • 自定义单元格宽高
        Updated
      • 自定义排序操作
        Updated
      • 自定义折叠/展开节点
        New
    • 交互
      • 基础交互
        Updated
      • 自定义交互
      • 隐藏列头
        Updated
      • 行列宽高调整
        Updated
      • 合并单元格
      • 滚动
        Updated
      • 复制与导出
        New
      • 高亮/选中单元格
        New
    • 分析组件
      • 简介
        New
      • 高级排序
        Updated
      • 维度切换
        Updated
      • 导出
        Updated
      • 分页
        Updated
      • 维度下钻
        Updated
    • 表格组件
      • 编辑表
      • 趋势分析表
        Updated
    • 高清适配
      Updated
    • 获取表格实例
    • 表格自适应
    • 获取单元格数据
      Updated
    • 注册 AntV/G 插件
      New
    • 透视组合图
      Experimental
    • Vue 3.0 组件 (停止维护)
  • 扩展阅读
    • 数据流处理
      • 透视表
      • 明细表
    • 布局流程
      • 透视表
      • 明细表
    • 性能介绍
      Updated
  • 贡献指南
  • 常见问题
  • S2 2.0 升级指南

性能介绍

上一篇
明细表
下一篇
贡献指南

Resources

Ant Design
Galacea Effects
Umi-React 应用开发框架
Dumi-组件/文档研发工具
ahooks-React Hooks 库

社区

体验科技专栏
seeconfSEE Conf-蚂蚁体验科技大会

帮助

GitHub
StackOverflow

more products更多产品

Ant DesignAnt Design-企业级 UI 设计语言
yuque语雀-知识创作与分享工具
EggEgg-企业级 Node 开发框架
kitchenKitchen-Sketch 工具集
GalaceanGalacean-互动图形解决方案
xtech蚂蚁体验科技
© Copyright 2025 Ant Group Co., Ltd..备案号:京ICP备15032932号-38

Loading...

介绍

S2 是 AntV 团队开发的可视化表格渲染引擎,上手成本低,具有丰富的交互操作,提供极佳的性能体验,具备高度灵活的扩展能力。

S2 可以用于实现明细表,也可以实现透视表,还可以实现趋势分析表等。

为了更好的理解本文,在阅读本文前,希望你能熟悉 S2 的使用,对 基本概念 有初步认知。

性能解读

在研究 S2 的性能之前,我们先熟悉其核心渲染链路,弄清楚哪些环节可能会耗时,优化从何做起。

S2 的渲染流程是:

  • 通过配置信息将原始数据处理,转换为以 行、列 纬度值为 path 的多维数组
  • 在此之后,通过 hierarchy 来改变自动生成的层级结构。然后通过 layout 更改任意行、列、单元格的坐标信息
  • 最后由 layoutResult 来确定行、列的笛卡尔交集的 dataCell 数据信息

如下图所示:

s2-data-process

明确核心渲染链路后,我们就可以发现,耗时环节「发生在数据转换」、「层级结构生成」、「单元格信息获取」三个阶段。接下来,我们看看 S2 如何性能优化。

性能优化

以如下透视表为例:

pivot sheet
const dataCfg={
fields:{
rows: ["province", "city"],
columns: ["type","sub_type"],
values: ["number"]
},
data:[
{
number: 7789,
province: "浙江省",
city: "杭州市",
type: "家具",
sub_type: "桌子"
},{
number: 2367,
province: "浙江省",
city: "绍兴市",
type: "家具",
sub_type: "桌子"
},
//...
]
}

数据结构

S2 渲染流程的第一步,就是把用户的明细数据转换为二维数组和具有层级的数据结构,在表格布局中会频繁的查询和排序,因此数据结构的设计显得尤为重要。

对于表场景查询频率非常高,透视表本身的展现形式也表达了一种树形结构,因此我们选择了构建树形结构 Map 来实现 rowPivotMeta 和 colPivotMeta。

另外,我们选择 Map 而不是 Object 实现树形结构,对于读取顺序和排序效率更高,对于删除 Key 的性能更友好,其 Map 具体类型定义可以参见 PivotMeta。数据结构如下:

// Meta
const rowsMeta: PivotMeta = {
浙江省:{
level: 1,
childField:"city",
children: {
杭州市:{
level: 1,
children: {},
},
绍兴市:{
level: 2,
children: {},
},
//...
},
},
四川省:{
level: 2,
childField:"city",
children: {
成都市:{
level: 1,
children: {},
},
绵阳市:{
level: 2,
children: {},
},
//...
},
},
};

通过这样的数据结构,我们就实现了表格行列树结构的前端表达。「形」有了后,我们就需要「魂」,也就是数据。

在 S2 中,我们需要将用户传入一维数据data通过内部的数据训练转为多维数组indexesData。这个多维数组是将行维度、列维度的 path 来组装的(底层是通过 lodash.set 实现),举个示例:

path

上图中,紫色单元格对应的坐标为:

  • 行坐标:浙江省 [1] - 杭州市 [1]
  • 列坐标:家具 [1] - 沙发 [2]。

因此单元格在多维数组中坐标为 [1, 1, 1, 2](多维数组每一个层级的 0 号位都是总计、小计专用位,明细数据序号都从 1 开始)。indexesData形如:

// 转换后的数据结构,
[
null,
// 浙江省
[
null,
// 杭州市
[
null,
// 家具
[
null,
{
"number": 7789,
"province": "浙江省",
"city": "杭州市",
"type": "家具",
"sub_type": "桌子"
},
{
"number": 5343,
"province": "浙江省",
"city": "杭州市",
"type": "家具",
"sub_type": "沙发"
}
],
// 办公用户
]
// 其他城市
],
// 四川省
[/*...*/]
]

查询数据时,首先从行列的 Meta 层级结构中获取对应的查询路径,然后根据查询路径即可在多维数组indexesData中拿到对应的数据。

因此在 S2 中查询数据不是循环遍历底层数据,基于层级结构和查询数组路径获取数据。在第一次遍历原始数据,生成必要的 Meta 和多维数组信息后,查询数据时间复杂度是 O(n)。此方案的优点是性能优异。

实际上 indexesData 还包含了单元格行列信息的前缀用于区分普通数据和下钻数据,所以其真正结构是: Record<string, RawData[][]>,其中 RawData[][] 对应上面的多维数组。

按需渲染

对于表格的单元格,S2 的策略是渲染可视区域内的单元格(按需渲染),滚动后动态新增和删除单元格,达到性能最佳。

通过 scrollX 和 scrollY,计算当前可视视窗中的单元格的节点索引。

const indexes = this.calculateXYIndexes(scrollX, scrollY); // indexes 结果是当前可视视窗节点的坐标索引集合。

对比当前可视视窗节点索引集合和上次索引集合的差值。

const { add, remove } = diffPanelIndexes(this.preCellIndexes, indexes); // add 和 remove 也是节点坐标索引集合

针对新增和删除的节点分别进行渲染和删除。

each(add, (x, y) => renderCell(x, y));
each(remove, (x, y) => getCell(x, y).remove());

通过按需渲染,极大的提高了 S2 的渲染效率,这也是我们支持百万级别数据渲染的原因。

缓存设计

对于数据的频繁读取,我们也做了性能提升,比如缓存数据读取结果、缓存字体宽度计算等。

/**
* 查找字段信息
*/
public getFieldMeta = memoize((field: string, meta?: Meta[]): Meta => {
return find(this.meta || meta, (m: Meta) => m.field === field);
});

另外,S2 还做了其他的一些优化来提升渲染效率,比如滚动合帧(解决滚动白屏问题)、懒渲染(解决多次重复渲染问题)。

未来规划

表格数据计算和布局设置涉及到大量的计算,未来我们会考虑把频繁复杂计算迁移到 web worker 中,保障主线程不被阻塞。

性能对比

表框架渲染时间对比

查看 100w 条数据实际性能表现:

  • 透视表
  • 明细表

详细的性能对比数据如下:

performance

备注:

  • 其中列头是实验次数,总计是平均渲染时间。
  • 100w 场景 orb 和 ReactPivot 卡死,无数据。

总结

从对比数据来看,优雅的数据结构设计和渲染方式使得 S2 在渲染上有着优势,极限测试下 500w 的数据也能正常渲染。