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

Why is the `sx` prop so much slower?

根据 MUI 自己的 doco, - 使用 sx 的组件渲染速度明显慢于使用其他样式机制的组件。

从表面上看,sx 只是做同样事情的另一种便利 API - 所以我不希望它有如此不同的性能配置文件。

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

我对优化它的可能性感到好奇,或者想出一个保留大部分可用性但忽略导致速度变慢的任何功能的折衷方案。

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

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

我相信 MUI 文档中的性能信息是使用此存储库的某些变体收集的:https://github.com/mnajdova/react-native-web。 react-native-web repo 被用作起点,因为它的“基准”包包含一个有用的框架,用于测量不同 React 元素 rendering/styling 方法的性能。

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

我的“Mount deep tree”基准测试结果

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

Styling Implementation Time in ms Implementation Desc
inline-styles 22.78 No styling engine, just use style prop
mui_sx_full 36.89 MUI Box sx prop with 17 CSS properties
mui_sx_medium 24.09 MUI Box sx prop with 9 CSS properties
mui_sx_minimal 18.15 MUI Box sx prop with 4 CSS properties
mui_styled_box 22.38 MUI styled MUI Box with 17 CSS properties
mui_styled_box_minimal 17.90 MUI styled MUI Box with 4 CSS properties
tss_react_makestyles 17.10 makeStyles from tss-react with 17 CSS properties
mui_styled 16.93 MUI styled div with 17 CSS properties
mui_styled_minimal 13.77 MUI styled div with 4 CSS properties
emotion_styled 16.69 Emotion styled div with 17 CSS properties
emotion_styled_minimal 12.76 Emotion styled div with 4 CSS properties
emotion_css 12.58 Emotion css div with 17 CSS properties

结论

  • MUI styled(例如import {styled} from '@mui/material/styles')只会增加少量开销 情感 styled.
  • tss-react 与 MUI styled.
  • 的执行方式类似
  • Emotion styled、Emotion css、MUI styled 和 MUI sx 道具在有 更多 CSS 属性传递给样式引擎。
  • sx 道具的性能比 styled API 的性能下降得更快 CSS 属性被传递给它。有 17 个 CSS 属性,性能比 styled API (2x) 差很多。
  • sx 道具对少量(例如 < 5)CSS 属性表现良好。特别是,如果你 已经在给定情况下使用 MUI 组件,没有有意义的性能差异 在用 styled 包装它或使用 sx 道具之间,如果你只是使用一个小数字 CSS 个属性。

sx 道具缓慢的原因是什么?

Is it a whole different styling engine or something?

这不是一个不同的样式引擎。为 sx 道具完成的工作的输出被送入主样式引擎的 styled API(例如 Emotion 或 styled-components);因此,将 sx 属性与 Box 组件一起使用肯定比在 div 上使用 styled 的等效样式慢,因为 sx 属性仍然使用 styled 最后,但先做额外的工作。

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

最终效果是对于每个 CSS 属性 都有许多查找和函数调用以查看 CSS 属性 是否需要转换甚至在值通过而没有变化的情况下。

I'm curious about the possibility of optimising it, or coming up with a compromise that retains most of the usability but omits whatever feature is causing the slowdown.

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

“保留大部分可用性”的主要折衷是使用Emotion的css prop directly. It can be used directly on elements in a similar fashion as the sx prop -- you just lose the shorthand notations and theme lookups that the sx prop provides. The theme lookups (e.g. for colors or spacing units) are easy to get directly from the theme by using the useTheme hook in the component. The theme.breakpoints API可以代替断点简写;尽管从 DX 的角度来看 sx 断点功能要好得多。