react-content-loader
react-content-loader copied to clipboard
High CPU usage
As shown in the above image the home page's cpu usage is always more than 40% and also more 20% in my app. I think this is abnormal, please confirm whether it is a bug or the normal phenomenon?
That's interesting. How did you benchmark that?
You can simply open the home page of this library (http://danilowoz.com/create-content-loader), then check the chrome's Task Manager., you'll see the cpu usage monitor.
Now I am pretty sure it's caused by the svg animation ( if I set {animate: false}
, the cpu usage will stay at almost 0. )
Thanks, I got your point. I can see that animations are taking significant CPU time (34-38%) at my system. I think that this is the issue with animations in general, as this chromium bug. However, we'll look into it and try to figure out a way to reduce CPU usage.
Thanks, it's not a big problem cause the content loader won't last for a long time, but fix it will be perfect.
I've tried some alternatives approaches and I reached these results, but I'm not sure if I should forward in one of these or wait for a chrome fix:
- Current: ~40%
- With one
<animate />
: ~53%
<linearGradient id={idGradient} x1="-100%">
<stop
offset="0%"
stopColor={primaryColor}
stopOpacity={primaryOpacity}
/>
<stop
offset="50%"
stopColor={secondaryColor}
stopOpacity={secondaryOpacity}
/>
<stop
offset="100%"
stopColor={primaryColor}
stopOpacity={primaryOpacity}
/>
<animate
attributeName="x1"
from="-100%"
to="100%"
dur={`${speed}s`}
repeatCount="indefinite"
/>
</linearGradient>
- With
backfaceVisibility: 'hidden', willChange: 'auto',;
in the<svg />
: >40%
Is there a way to push SVG animations to the GPU?
We're seeing similarly high CPU usage when animate=true for React Native as well.
I was using react-content-loader as a placeholder while during development and I couldn't figure out why my computer was soooo slow all the time. Then I checked the task manager and finally blamed it on the animation. Without animation everything is fine.
I'm seeing similar results regarding my CPU usage as well. I'm using React (for the web) on development mode and for comparison, those are the CPU usage without and with animate={false}
on my page:
With animate={false}
Without animate={false}
FIY: I'm using react-content-loader
version 5.0.4 in here.
I actually have a huge CPU usage on this page https://danilowoz.com/create-content-loader/ but it's still close to 0 on this codesandbox https://codesandbox.io/s/6x2414oqln.
See the following proposal @danilowoz. The essence is to use SVG mask
instead of clippath
. Fill the rectangle in white and mask the content placeholder shapes black. That way, the SVG's element background becomes visible where the mask is black. Now you can use CSS linear-gradient for the background which is animated by changing the background position.
Tested in latest firefox, low CPU usage. Didn't check for compatibility with other browsers.
SVG:
<svg width="100%" viewBox="0 0 800 350" className='loader-animated-bgr'>
<rect x="0" y="0" width="100%" height="100%" fill='white' mask="url(#mymask)">
</rect>
<defs>
<mask id="mymask">
<rect id="bg" x="0" y="0" width="100%" height="100%" fill="white" />
<!-- TODO: insert any shapes filled black -->
</mask>
</defs>
</svg>
CSS:
$col-bgr: #ecebeb;
$col-accent: #e0e0e0;
.loader-animated-bgr {
background: linear-gradient(90deg, $col-bgr, $col-bgr 25%, $col-accent 45%, $col-accent 55%, $col-bgr 75%, $col-bgr);
background-size: 400% 100%;
animation: loader-animation 3s ease infinite;
}
@keyframes loader-animation {
0% { background-position: 100% 0% }
100% { background-position: 0% 0% }
}
Have a nice day!
This reporting in Chromium might help: https://bugs.chromium.org/p/chromium/issues/detail?id=1141881
Also most likely related to this - when using Detox (React Native) to test, tests just hang whenever the content loader is present. Might be something to do with how Animate lib is interacted with, maybe some unresolved promise.
If I set animate={false} it works well.
I did`t research much this topic, but can add when I trying to run tests - every time snapshot are updated, without any changes in spec file, and every time updates below property of <RNSVGRect /> ( symbols in **). Test passes very long time, and seems like an infinity loop, one time I even got error with full memory.
clipPath=" **zrpmk0p** -animated-diff"
@AND-GORNIY regarding the id
issue, I'd recommend the following issue https://github.com/danilowoz/react-content-loader/issues/78, it introduces the prop uniqueId
in order to manage this kind of situation. Unfortunately, it needs somehow a unique value, and in case the user doesn't provide any one, the library needs to generate a random one.
Make sense?
Found an interesting sort of solution to this problem:
"As with the hero of any story, however, there must be a fall from grace. For animated SVGs, this fall occurs in CPU usage. The inclusion of just a few on a webpage can cause the CPU usage of a browser to jump by several tens of percentage points. Viewing such a page on even modern laptops will cause the machine to whirr like it’s trying to take flight and heat up like a bacon griddle.
Fortunately, redemption for our hero comes easily and quickly in the form of CSS hardware acceleration.
If you’re unfamiliar with the concept, the idea is to give a troublesome element the style transform: translateZ(0);
. This gives the element its own render layer, and lets the GPU (who’s better at this kind of work anyway) take the hard number crunching away from the overloaded CPU."
Worked well for me, reduced the max workload experienced from 40-50% to an average of 20-30% (still a lot, but an improvement).
I fixed this by re-implementing the loader to clip a div instead of a rect. I also had to rely on animating opacity instead of backgroundColor/fill.