-
Notifications
You must be signed in to change notification settings - Fork 48.3k
improve performance of style tags that use precedence #32957
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
base: main
Are you sure you want to change the base?
Conversation
fe605aa
to
c200aa6
Compare
Comparing: bc6184d...7c917f5 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
function appendStyleRule(style: HTMLStyleElement, cssText: string) { | ||
try { | ||
if (style.sheet) | ||
style.sheet.insertRule(cssText, style.sheet.cssRules.length); | ||
else style.textContent += cssText; | ||
} catch (e) { | ||
style.textContent += cssText; | ||
} | ||
} |
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.
Please take my feedback with a grain of salt. I'm not a React team member - but we were chatting with @gnoff about most of this already.
I think this change should be reverted (for now). I totally agree this is something that will have to be implemented in some capacity at some point but there are open design questions around this.
It feels like, at the moment, this breaks the core assumption that a single resource is represented by a single element. OTOH, not many tests were affected by this change and that makes me doubt a little bit in my interpretation of the change.
All in all, I'd focus first on caching insertion points for each precedence to avoid expensive and redundant querying.
Summary
Currently, every time we insert a new style tag that has precedence, we first need to run 2 querySelectorAll calls. If we want to render 400 style tags, we'll need to run querySelectorAll 800 times. This is fairly slow.
Additionally, every time we encounter a new style tag react will create a new style tag in the DOM, and will (as far as I can tell) make no attempt to remove that style tag at any point. So the process of inserting itself will get slower as we insert more and more styles.
We can address the performance in this specific case by inserting nodes less often:
a few other random notes
fixes #32806
fixes #30739
How did you test this change?
I've built this version of react and patched it into a few projects that were having performance issues. I'm planning on doing this again (I've tweaked a few things) and will update these results when I've done that.
in one such expensive render:
the entire process (including the browsers style recalculation) went from 2.11s to 504.34ms
the react portion of that process went from 1.47s to 26.91ms
flushMutationEffects (the previously slow part) went from 1.45s to 7.58ms
in one more extreme case:
the entire process (including the browsers style recalculation) went from 9.57s to 600.18ms
the react portion of that process went from 8.63s to 41.05ms
flushMutationEffects (the previously slow part) went from 8.61s to 6.67ms
These two examples are obviously not fully comprehensive (I could fabricate a fairly comprehensive example case if anyone is interested) but they do roughly represent the level of improvement I've seen in my testing.