为什么 `sx` 属性这么慢?

Sho*_*orn 12 reactjs material-ui

根据 MUI 自己的 doco 和这个答案- 使用sx渲染的组件比使用其他样式机制的组件慢得多。

从表面上看,它看起来sx只是一个替代的便利 API,用于执行相同的操作 - 所以我不希望它具有如此不同的性能配置文件。

我的问题是:为什么组件的渲染速度sx如此之慢 - 它的作用有何不同?它是一个完全不同的造型引擎还是什么?

我很好奇优化它的可能性,或者提出一种折衷方案,保留大部分可用性,但忽略导致速度减慢的任何功能。

请注意,这个问题是关于“为什么性能如此不同”,而不是“为什么你认为差异不重要”。

Rya*_*ell 39

当我开始深入研究这一点时,我意识到我需要测量不同场景的性能,以便对我对道具性能方面的理解有信心sx

MUI 文档中的性能信息是使用可在此处找到的基准收集的: https: //github.com/mui/material-ui/tree/v5.13.2/benchmark/browser

我相信这些基准的早期版本是基于此存储库的某些变体: https: //github.com/mnajdova/react-native-web。React-native-web 存储库被用作起点,因为它的“基准”包包含一个有用的框架,用于测量不同 React 元素渲染/样式方法的性能。

我在这里创建了自己的版本:https ://github.com/ryancogswell/mui-style-benchmarks 。您可以以此为起点进一步深入研究。以下是我所做的测量和我的结论。

我的“山深树”基准测试结果

此测试渲染 639 个元素,每个元素大约有 17 个 CSS 属性,但情况(“..._minimal”、“..._medium”)除外,这会减少 CSS 属性的数量以显示性能影响。

样式实施 时间(毫秒) 实现说明
内联样式 22.78 没有造型引擎,只需使用styleprop
mui_sx_full 36.89 sx具有 17 个 CSS 属性的MUI Box属性
mui_sx_medium 24.09 sx具有 9 个 CSS 属性的MUI Box属性
mui_sx_minimal 18.15 sx具有 4 个 CSS 属性的MUI Box属性
mui_styled_box 22.38 MUI styledMUIBox具有 17 个 CSS 属性
mui_styled_box_minimal 17.90 MUI styledMUIBox具有 4 个 CSS 属性
tss_react_makestyles 17.10 makeStyles来自tss-react17 个 CSS 属性
mui_styled 16.93 styled div 具有 17 个 CSS 属性的MUI
mui_styled_minimal 13.77 styled div具有 4 个 CSS 属性的MUI
情感风格 16.69 styled div具有 17 个 CSS 属性的情感
情感风格最小 12.76 styled div4 个 CSS 属性的情感
情感CSS 12.58 css div具有 17 个 CSS 属性的情感

结论

  • MUI styled(例如import {styled} from '@mui/material/styles')只给 Emotion 增加了少量的开销styled
  • tss-react 的执行方式与 MUI 类似styled
  • 当传递给样式引擎的 CSS 属性越多时, Emotion styled、 Emotion css、 MUIstyled和 MUI sxprop 的成本都会更高。
  • 随着更多 CSS 属性传递给prop,prop的性能sx比 API 下降得更快。styled由于有 17 个 CSS 属性,性能比styledAPI 差很多(2 倍)。
  • sxprop 对于少量(例如 < 5)的 CSS 属性表现得很好。特别是,如果您已经在给定情况下使用 MUI 组件,并且仅使用少量 CSS 属性,那么使用 prop包装它styled或使用prop 之间没有有意义的性能差异。sx

造成道具缓慢的原因是什么sx

它是一个完全不同的造型引擎还是什么?

它不是一个不同的造型引擎。为 prop 所做的工作的输出sx被馈送到styled主样式引擎的 API(例如 Emotion 或 styled-components);因此,将sxprop 与Box组件一起使用肯定会比styled在 a 上使用的等效样式慢div,因为prop最终sx仍会使用,但首先会执行额外的工作。styled

道具完成的额外工作是什么sx

最终效果是,对于每个 CSS 属性,都会进行多次查找和函数调用,以查看 CSS 属性是否需要转换,即使在值未经更改地传递的情况下也是如此。

我很好奇优化它的可能性,或者提出一种折衷方案,保留大部分可用性,但忽略导致速度减慢的任何功能。

我确信该sx道具的性能改进是可能的,但我不认为有任何灵丹妙药可以轻松地使其更快。相反,它可能需要大量的小改变,每一个改变都几乎无法衡量,但累积起来会带来不错的改进。挑战在于进行这些更改,同时又不会使代码变得更复杂和/或更难维护和/或更容易出错。

“保留大部分可用性”的主要妥协是直接使用 Emotion 的css prop。它可以以与 prop 类似的方式直接在元素上使用sx- 您只是丢失了 prop 提供的速记符号和主题查找sx。通过使用组件中的useTheme 挂钩,可以轻松地直接从主题中获取主题查找(例如颜色或间距单位) 。可以使用theme.breakpoints API代替断点简写;尽管sx从 DX 的角度来看,断点功能要好得多。

我个人的方法是用于tss-react大多数样式(这允许在从 v4 迁移到 v5 时从基于 JSS 的直接迁移makeStyles/useStyles),然后sx在仅出现少量次的组件上使用该 prop 来实现一些一次性样式给定的页面。