-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TouchRipple] Avoid calling clearTimeout()
to improve performance
#37512
Conversation
Netlify deploy previewhttps://deploy-preview-37512--material-ui.netlify.app/ Bundle size report |
Ping @gzrae, not sure who to ping to get feedback here. |
clearTimeout()
clearTimeout()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch! As for the general fix, we could introduce a wrapper around clearTimeout that checks if a timeout id is valid, but then we'll have to make sure this wrapper is called every time instead of the native function. I suppose adding checks before clearTimeout
is more explicit.
I've merged in this datagrid PR a wrapper for timeout, it handles this case and doesn't allocate anything after the first render so it's super efficient. We can migrate it to core at some point. |
clearTimeout()
clearTimeout()
to improve performance
@romgrk 👌 I created a quick reproduction for this performance issue. import * as React from 'react';
import Button from '@mui/material/Button';
export default function BasicButtons() {
const [show, setShow] = React.useState(true);
return (
<div>
<button onClick={() => {
setShow(false);
}}>
Hide
</button>
{show ? <div>
{Array.from(new Array(1000)).map((x, index) => (
<Button key={index} variant="contained">Contained</Button>
))}
</div>
: null}
</div>
);
} On a x4 slowdown CPU (relative to my Apple M1 Pro), we are spending 60ms to unmount 1,000 buttons. It gets really absurd when unmounting Tooltips: import * as React from 'react';
import Tooltip from '@mui/material/Tooltip';
export default function BasicButtons() {
const [show, setShow] = React.useState(true);
return (
<div>
<button onClick={() => {
setShow(false);
}}>
Hide
</button>
{show ? <div>
{Array.from(new Array(1000)).map((x, index) => (
<Tooltip title="hello">
<button key={index}>Contained</button>
</Tooltip>
))}
</div>
: null}
</div>
);
} It looks like a quick-win someone should take on, e.g. maybe with the helper Romain proposed. I created a task for it: https://www.notion.so/mui-org/clearTimeout-safeguard-d469f036aa3b4d49b503fd312863ef5b, but best to move it to GitHub issues (I didn't to avoid getting notifications, but still created the task as it looks too good to get forgotten). |
I've been profiling the X DataGrid as part of mui/mui-x#9037, I've noticed that the
clearTimeout()
calls coming fromTouchRipple.js
are consistently taking about 5% of the CPU time for each of our scroll events on blink-based browsers.I'm guessing
clearTimeout
crosses the boundary into C++ code, which isn't great for performance. This PR avoids calling the function if no timeout has been started.I'm guessing the same performance hit applies to all
clearTimeout()
calls in the codebase, I'm not sure if you'd like to find a more general solution. Let me know if you prefer the change to be applied to allclearTimeout
calls.