I have around 15-20 child aura components sitting inside the aura parent component. Just you know this is a legacy system and I can not do much other than improving the page performance, my question is how can I improve the performance of the page loads?, is that possible to load other components based on service side call finishes and then load one component at a time... something to the effect? Appreciate if you guys have worked in a similar situation or any recommendations is welcome.
1 Answer
You'll want to read about my explanation of the boxcar effect. Basically, everything that gets queued up in connectedCallback
(LWC) or aura:valueInit
(Aura) handlers will all go as a single transaction, and Apex is not multithreaded, so each request has to be handled in serial. As such, there are a few important things to consider.
First, you can optimize your Apex code to be as fast as possible. Try to keep any methods that must be called as trivial as possible. Don't use JSON encoding (JSON.serialize
and JSON.deserialize
), don't do complicated calculations on data, etc. Just return what you need as fast as possible. Allow the platform to do any JSON serializing on your behalf as much as possible.
Second, you can add a small delay to the methods randomly in order to break up the boxcar effect. Adding any delay on load at all avoids the initial boxcar effect. For example, this small change to your code should give major improvement:
let action = component.get("c.someMethod");
action.setCallback(this, function(response) {
// Write your handler here
})
action.setParams({ params })
setTimeout($A.getCallback(function() { $A.enqueueAction(action) }), Math.random()*1e3)
Here, each component calls its opening initialization randomly within a second of loading, but not immediately on initial load. This breaks up the initial boxcar. Also, if you know the order you'd like to use for loading, consider setting static values. You might have some load at 100ms, some at 250ms, etc. If you do this, keep in mind you get five separate threads before the boxcar effect after initial rendering.
Third, for anything that doesn't need to go immediately, use setBackground
. This will allow higher priority calls to go first. It's recommended that you use this for anything that you anticipate may take more than five seconds to respond. Callouts and complicated queries might be better off using the background mode. You can combine this with the previous concept to minimize the initial boxcar loading penalty.
Fourth, as you've hypothesized, if you can somehow coordinate rendering cycles, it might be beneficial to have just a few components load at once with some judicial use of aura:if
; just be sure that you set the default state for rendering to false to avoid excessive render cycles; check your Developer Console, the F12 button, to see if you get any warnings regarding this behavior.
Also, keep in mind you can use Aura.Component[]
to dynamically render components at runtime, so you might use this to render your UI in JavaScript, rather than using aura:if
. Some people find this way to be easier when the number of components are potentially dynamic or to reduce the markup clutter that you can get with many aura:if
elements. It's about the same performance-wise, so use whichever makes more sense.
-
Is there a reason not to simply set all these components as using setBackground, since this should break any boxcarring (at least for explicit requests to the server)?– Phil WCommented Mar 5, 2022 at 5:27
-
I also recommend digging further back in the Q&A threads than the answer you refer to since there is other information about how well, or not, setTimeout works.– Phil WCommented Mar 5, 2022 at 6:01
-
(I personally dislike and avoid use of connectedCallback as a lifecycle hook, and your additional finding around boxcarring here is another reason to avoid it!)– Phil WCommented Mar 5, 2022 at 6:03
-
@PhilW Setting everything to background has a similar effect to not using it at all; you'll end up with a large boxcar right behind the initial load, which can impact the UI while everything catches up, except kind of worse because the UI is visible, but not responsive. I will admit, setTimeout can be a bit finnicky sometimes, but that usually has more to do with accidentally setting the wrong
this
somehow (JS is notorious for that).– sfdcfox ♦Commented Mar 5, 2022 at 13:28 -
@PhilW Salesforce recommends using the afterRender/renderedCallback hooks, which is acceptable in many cases, but setTimeout, used correctly, breaks up the boxcars into manageable chunks. Of course, as the answer I linked to points, another answer states that orchestration is ideal; and I agree with that in principle. Unfortunately, if you do go that way, it's a much more serious refactor than just using setTimeout and letting things work more or less okay.– sfdcfox ♦Commented Mar 5, 2022 at 13:30