Skip to content

Conversation

@Alexzjt
Copy link
Contributor

@Alexzjt Alexzjt commented Sep 9, 2025

👀 PR includes

✨ Feature

  • New feature

🎨 Enhance

  • Code style optimization
  • Refactoring
  • Change the UI
  • Improve the performance
  • Type optimization

🐛 Bugfix

  • Solve the issue and close #0

🔧 Chore

  • Test case
  • Docs / demos update
  • CI / workflow
  • Release version
  • Other ()

📝 Description

在S2百万数据交叉表滚动场景下(1649个元素),S2花费了巨量的时间在创建、计算和渲染单元格上,伴随着大量单元格、line、rect、text等Destroy与new。
大量的对象在短时间内被创建然后又被废弃,会导致频繁的垃圾回收和较高的性能开销。
所以有必要采取复用已有DisplayObject这样性能友好的写法来提高性能。

依赖 antvis/G#2001

🖼️ Screenshot

Before After

🔗 Related issue link

🔍 Self-Check before the merge

  • Add or update relevant docs.
  • Add or update relevant demos.
  • Add or update test case.
  • Add or update relevant TypeScript definitions.

Alexzjt and others added 30 commits March 25, 2025 15:47
# Conflicts:
#	packages/s2-core/src/facet/base-facet.ts
…header

# Conflicts:
#	packages/s2-core/src/cell/header-cell.ts
# Conflicts:
#	packages/s2-core/package.json
#	packages/s2-core/src/sheet-type/spread-sheet.ts
#	pnpm-lock.yaml
…_0718

# Conflicts:
#	packages/s2-core/src/group/grid-group.ts
#	packages/s2-core/src/utils/g-renders.ts
#	packages/s2-react/playground/components/BigDataSheet.tsx
…header

# Conflicts:
#	packages/s2-core/src/cell/DataCellPool.ts
#	packages/s2-core/src/facet/base-facet.ts
#	packages/s2-core/src/utils/g-renders.ts
@github-actions github-actions bot added the next 2.0-next 版本的问题 label Sep 9, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Sep 9, 2025

你好 @Alexzjt,非常感谢你的贡献.
为了让代码更健壮, 请根据 贡献指南 补充相应单元测试 (文档改动或其他特殊场景除外), 如果有 API 改动, 请修改 相应的文档.
同时请检查 linttest 相关 CI 是否通过, 如果失败, 请点击 [Details] 按钮查看, 并根据日志修复.

Hello, @Alexzjt, Thanks for your contribution. In order to make the code more robust, please add the corresponding unit tests, and update the docs if there are API changes.
At the same time, please check whether the CI related to lint and test passes. If the CI fails, please click [Details] button to check and repair according to the log.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @Alexzjt, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求的核心目标是大幅提升表格在百万数据量滚动时的渲染性能,旨在达到 50FPS 的流畅度。这主要通过实现全面的图形对象复用和引入单元格对象池机制来达成,从而减少了不必要的对象创建和销毁,优化了渲染循环。

Highlights

  • 核心性能优化:图形对象复用: 通过引入 batchSetStylecreateOrUpdateRect 等工具函数,实现了单元格(数据单元格、行列头单元格)、边框、背景、文本、链接、条件图标以及网格线等图形元素的复用渲染。这意味着在滚动或更新时,不再频繁创建和销毁图形对象,而是更新现有对象的属性,显著减少了垃圾回收的压力和渲染开销。
  • 单元格对象池机制: 新增了 BaseCellPool 及其子类(ColCellPoolDataCellPoolRowCellPool),为行列头和数据单元格提供了高效的复用和回收机制。当单元格不再可见时,会被放入对象池等待下次复用,进一步提升了大数据量下的滚动性能。
  • 实验性功能开关: 在 s2Options 中引入了 future.experimentalReuseDataCell 实验性功能开关,允许开发者选择性地启用数据单元格的复用特性,便于测试和逐步推广。
  • 渲染引擎配置增强: 现在可以通过 s2Options.rendererConfig 配置 AntV/G 渲染引擎的参数,提供了更灵活的底层渲染控制能力。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions

This comment was marked as duplicate.

@github-actions github-actions bot added 🚨 test failed 单元测试挂了 🚨 lint failed 静态检查失败 labels Sep 9, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

本次 PR 旨在通过复用单元格来提升滚动性能,这是一个非常棒的优化方向。代码的改动范围较广,涉及了单元格基类、各种头单元格、数据单元格以及 Facet 和 Header 的实现,核心思路是在已有图形和单元格对象上更新属性,而不是频繁销毁和创建,这能有效减少 GC压力并提升渲染速度。

代码整体实现得很好,特别是引入了单元格对象池(Cell Pool)和一系列工具函数来支持复用逻辑。

我发现了一些可以进一步优化的地方,主要集中在对象池的实现上,希望能帮助你让这次性能优化更加彻底。具体请看我的详细评论。

@Alexzjt
Copy link
Contributor Author

Alexzjt commented Sep 9, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 通过引入对象池和复用图形元素(单元格、形状、图标等)来显著提升滚动性能,这是一个非常棒的性能优化。核心改动包括:

  1. 为行头、列头和数据单元格实现了对象池,以减少频繁的对象创建和销毁。
  2. 在单元格渲染逻辑中,对背景、边框、文本、图标等图形元素进行了复用,而不是每次都重新创建。
  3. 引入了 batchSetStyle 工具函数,利用 G 的 setAttributes 批量更新样式,减少不必要的重绘事件,进一步提升性能。
  4. GuiIcon 添加了 reRenderupdatePosition 方法,支持更高效的图标更新。
  5. 通过 future 配置项引入了实验性功能开关 experimentalReuseDataCell,这是一个很好的实践,可以安全地引入重大变更。

整体代码改动清晰地遵循了“复用代替创建”的原则,对提升大数据量下的滚动流畅度有很大帮助。代码质量很高,但有几个可以改进的地方,主要关于类型安全。

Comment on lines +659 to +662
public setHeaderConfig(headerConfig: ColHeaderConfig) {
super.setHeaderConfig(headerConfig);
// this.drawResizeArea();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

this.drawResizeArea() 这行代码被注释掉了。请问这是有意的吗?如果不再需要,建议移除这行注释掉的代码以提高代码清晰度。如果是在某些条件下需要,或许可以添加注释说明暂时禁用的原因。

Comment on lines +251 to +256
this.scrollGroup.childNodes.forEach((colCell: ColCell) => {
if (!this.isColCellInRect(colCell.getMeta())) {
colCell.getMeta().belongsCell = null;
this.colCellPool.release(colCell);
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

forEach 循环中使用 @ts-ignore 并将 colCell 断言为 ColCell 类型不是类型安全的。childNodes 数组的类型是 DisplayObject[],其中可能包含非 ColCell 类型的实例。如果未来 scrollGroup 中添加了其他类型的对象,这可能会导致运行时错误。建议添加类型检查来增加代码的健壮性。

Suggested change
this.scrollGroup.childNodes.forEach((colCell: ColCell) => {
if (!this.isColCellInRect(colCell.getMeta())) {
colCell.getMeta().belongsCell = null;
this.colCellPool.release(colCell);
}
});
this.scrollGroup.childNodes.forEach((child) => {
if (child instanceof ColCell) {
if (!this.isColCellInRect(child.getMeta())) {
child.getMeta().belongsCell = null;
this.colCellPool.release(child);
}
}
});

Comment on lines +240 to +245
this.scrollGroup.childNodes.forEach((rowCell: RowCell) => {
if (!this.isCellInRect(rowCell.getMeta())) {
rowCell.getMeta().belongsCell = null;
this.rowCellPool.release(rowCell);
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

col.ts 中的问题类似,此处使用 @ts-ignore 并将 rowCell 断言为 RowCell 类型不是类型安全的。childNodes 数组包含 DisplayObject,增加一个类型检查可以防止潜在的运行时错误。

Suggested change
this.scrollGroup.childNodes.forEach((rowCell: RowCell) => {
if (!this.isCellInRect(rowCell.getMeta())) {
rowCell.getMeta().belongsCell = null;
this.rowCellPool.release(rowCell);
}
});
this.scrollGroup.childNodes.forEach((child) => {
if (child instanceof RowCell) {
if (!this.isCellInRect(child.getMeta())) {
child.getMeta().belongsCell = null;
this.rowCellPool.release(child);
}
}
});

renderLine(this.gridGroup, {
x1: x - halfVerticalBorderWidthBorderWidth,
x2: x - halfVerticalBorderWidthBorderWidth,
const children = this.gridGroup.children as Line[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

this.gridGroup.children as Line[] 这个类型断言不是类型安全的。它假设 gridGroup 只会包含 Line 对象。如果将来有其他类型的 DisplayObject 被添加到 gridGroup 中,这可能会导致运行时错误。建议添加注释来明确这个设计约束,以防止未来的 bug。

Comment on lines +19 to +32
export function createOrUpdateRect(
propertyPath: string,
style: RectStyleProps,
) {
// @ts-ignore
const context = this as any;
const obj = get(context, propertyPath);

if (!obj) {
set(context, propertyPath, new Rect({ style }));
} else {
batchSetStyle(obj, style);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

createOrUpdateRect 函数中使用 // @ts-ignorethis as any 绕过了 TypeScript 的类型安全检查。虽然这个工具函数很方便,但如果 propertyPath 不正确,代码将更难推理且更容易出现运行时错误。可以考虑是否有可能实现一个类型更安全的版本,例如通过显式传递目标对象而不是依赖 this 上下文。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🚨 lint failed 静态检查失败 next 2.0-next 版本的问题 🚨 test failed 单元测试挂了

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants