Skip to content

Conversation

@KAROTT7
Copy link
Contributor

@KAROTT7 KAROTT7 commented Dec 23, 2021

性能优化:当存在上百个组件时,优化 node class 增删行为造成的卡顿问题

相关问题链接:ant-design/ant-design#32681

解决方案:

  • 废弃 activeKeydefaultActiveFirst API, 这两个 API 的作用只是给元素设置背景色
  • 重构 useActive 方法,移除 active 属性并重命名为 useMouseEvents
  • 优化 useAccessibility 方法,移除 activeKey 和 triggerActiveKey 参数并更改相关逻辑
  • 增加 performance.tsx example
  • 更新 assets/index.less 文件

TODO:在非 inline 模式下,通过键盘操作时,子菜单隐藏时,父菜单背景色会闪烁,原因在与 tryFocus 和 triggerAccessibilityOpen 方法不同步

@afc163
Copy link
Member

afc163 commented Jan 17, 2022

看下 CI

@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Jan 19, 2022

OK,我会尽快修复 CI 问题

* remove `activeKey` and `defaultActiveKey` api

* add preformance.tsx demo for preformance

* remove or rewrite some test cases
@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 2, 2022

@afc163 ok 了,看看

@afc163
Copy link
Member

afc163 commented Feb 10, 2022

@zombieJ @MadCcc

@codecov
Copy link

codecov bot commented Feb 10, 2022

Codecov Report

Merging #429 (7f97604) into master (5aeca9e) will increase coverage by 0.15%.
The diff coverage is 100.00%.

Impacted file tree graph

@@             Coverage Diff             @@
##           master      #429      +/-   ##
===========================================
+ Coverage   99.84%   100.00%   +0.15%     
===========================================
  Files          25        25              
  Lines         652       628      -24     
  Branches      169       162       -7     
===========================================
- Hits          651       628      -23     
+ Misses          1         0       -1     
Impacted Files Coverage Δ
src/Menu.tsx 100.00% <ø> (ø)
src/context/MenuContext.tsx 100.00% <ø> (ø)
src/MenuItem.tsx 100.00% <100.00%> (ø)
src/SubMenu/index.tsx 100.00% <100.00%> (ø)
src/hooks/useAccessibility.ts 100.00% <100.00%> (ø)
src/hooks/useMouseEvents.ts 100.00% <100.00%> (ø)
src/hooks/useUUID.ts 100.00% <100.00%> (+9.09%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5aeca9e...7f97604. Read the comment docs.

@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 11, 2022

有些代码覆盖率问题,请等我加些测试代码

* add test cases for coverage

* rename .effect to .active-effect

* focus ancestor element after click item in `horzontal` or `vertical` mode
@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 11, 2022

修改已完成,本地代码测试和覆盖率测试均已通过

focusMenuElement?: HTMLElement,
offset: number = 1,
) {
// Key on the menu item will not get validate parent container
Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove unreachable codes

@MadCcc
Copy link
Member

MadCcc commented Feb 15, 2022

覆盖率还是不够啊

@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 15, 2022

好的,我在排查下

@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 16, 2022

@MadCcc 好了

@afc163
Copy link
Member

afc163 commented Feb 16, 2022

给一个性能分析?

@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 16, 2022

@afc163 抱歉,没做过这方面,想问下性能分析我该以怎样的形式给你?是直接在评论里写更改前后的性能对比?

@afc163
Copy link
Member

afc163 commented Feb 16, 2022

直接写就好了。

@KAROTT7
Copy link
Contributor Author

KAROTT7 commented Feb 16, 2022

性能分析:

  1. 性能瓶颈原因
    • 使用 node class 控制背景色:通过源码发现 activeKeydefaultActiveFirst 用来给 MenuItem 和 SubMenu 添加 *-active class 来控制节点背景色;当组件过多时,大量的 mouseenter 和 mouseleave 事件会造成 node class 增删消耗导致页面卡顿;考虑到 selectedKeysopenKeys api 也会给组件设置 class,完全可以通过给 *-selected *-open 来控制背景色,同时使用完全不会造成页面重新渲染的 element:focuselement:hover 等 css 属性来替代 mouseenter 和 mouseleave 事件
    • 另一个造成瓶颈的原因是未对 parseChildren(children) 代码做缓存处理(已提交PR performance: cache children to improve performance #426
  2. 提供 preformance 示例,通过使用 mouseenter 和 mouseleave 事件来测试性能,比如匀速手动划过组件。(PS. 下列测试结果可能因电脑环境不同而不同,可以换成倍数理解)
    • MenuItem
      • 更改前:130 个组件则会有明显卡顿
      • 更改后:即使是 5000 个以上的组件都不会卡顿,因为不再有页面渲染
    • SubMenu + MenuItem
      • 更改前:80*80 开始会有卡顿
      • 更改后:160*160 开始才会卡顿,性能提升一倍;缓存 parseChildren 后则会继续提升到 240*240
    • SubMenu + SubMenu + MenuItem
      • 经测试性能相差不是很大,基本都在 50*50*50 就会卡顿,不过缓存 parseChildren 后则会继续提升到 80*80*80

PS. 组件过多会造成初始渲染卡顿,不过这是另一个话题

@afc163
Copy link
Member

afc163 commented Feb 16, 2022

@MadCcc 继续跟进吧


// Active control
activeKey?: string;
defaultActiveFirst?: boolean;
Copy link
Member

Choose a reason for hiding this comment

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

不能删除 API

Copy link
Contributor Author

Choose a reason for hiding this comment

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

既然不能删除这两个 API 那我暂时想不到其他的方案,因为组件过多时确实是 node class 增删行为造成的卡顿。
不过可以通过这个 PR (#426),对 parseItems 方法进行缓存也能有效提升一倍的性能,可以复制以下代码进行测试:

// 在我的电脑,未使用 useMemo 缓存时, count = 130 会有明显卡顿,使用后 count = 260 才会有明显卡顿
const count = 260
export default () => (
  <div style={{ width: 200 }}>
    <Menu
      defaultSelectedKeys={['0', '0 - 0']}
    >
      {new Array(count).fill(0).map((m, i) => {
        const title = 'item - ' + i

        return (
          <SubMenu key={i} title={title}>
            {new Array(count).fill(0).map((n, index) => {
              const key = i + ' - ' + index
              const subTitle = title + ' - ' + index

              return (
                <MenuItem key={key}>{subTitle}</MenuItem>
              )
            })}
          </SubMenu>
        )
      })}
    </Menu>
  </div>
);

Copy link
Member

Choose a reason for hiding this comment

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

嗯,现在提供了 items,准备下个大版本去掉语法糖的用法。解析 Node 太过昂贵,也缺少优化的空间。

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants