[SalesForce] Lightning Components: Why is the rendering of 3-level nested ‘s so slow

I have been working with a nested iteration and it is causing a delay of >3 seconds AFTER loading things from the APEX controller.

The APEX response itself is fast, so I'm not looking for any APEX optimizations. Something seems to happen in the Lightning framework during rendering of the iteration.

Below is a general sourcecode example.

Assume it will iterate over 10 accounts having 10 contacts and on each contact 100 products should be put inside a select as options. Further assume there is no chance for re-using the same 100 products for all contacts, because there might be different sets of selectable products for each contact later (not shown in the code, but assume)

Apex

@AuraEnabled public static Map<String, object> loadAccountsAndProducts() {
    return new Map<String, object> { 
        'Accounts' => [ select Id, Name, (select Id, LastName from Contacts) from Account ]
        ,'Products' => [ select Id, Name from Product2 ]
    };
}

JS Controller

action = cmp.get("c.loadAccounts");
action.setCallback( null, 
function(callbackResult) { 
   if(callbackResult.getState()=='SUCCESS') {     
      cmp.set("v.accounts",callbackResult.getReturnValue().Accounts );
      cmp.set("v.products",callbackResult.getReturnValue().Products );
   }
});
$A.enqueueAction( action );

Markup

<aura:iteration items="{! v.accounts }" var="account"
   <aura:iteration items="{! account.Contacts }" var="contact">
      <lightning:select name="selectItem" label="{!contact.LastName}">
          <aura:iteration items="{! v.products }" var="product">
              <option value="">{!product.Name}</option>
          </aura:iteration>
      </lightning:select>
    </aura:iteration>
</aura:iteration>

Questions

  • Are there any known performance degradations using massivly nested aura iterations? Can I expect that (superfast APEX response assured) 3 nested iterations of 10 x 10 x 100 in total 10k elements are fast (like less than 1 second for rendering)?
  • Are there any best practices on how to debug performance degradations in Lightning Components? After ruling out apex as bottleneck, where should i begin to investigate? Using which tools?

Best Answer

This would be MUCH faster to do in your Apex controller than it would be to do in your lightning controller. The reason this is taking so long is because your iteration will look something like this:

// Outer loop
For(Account a:accounts){

    // Inner Nested Loop 1    
    // Loop through all of the accounts
    // to get related contacts (account.contacts)

    For(Contact c:contacts){ 
        //Add each related contact from the current account's query results  
        Contacts.add(Contacts.LastName);

        // Inner Nested Loop 2
        // loop through products for each Account Contact

        For(Product p:Products){
           OptionValue.add(p.Name);
        {

    }
}

To do the above, you go through every related contact that was returned for the Account to pull them out. Because you want them separated, you might have been better off to do that in the controller. I see no relationship between Product and Account.Contact. This is what seems to be killing your performance. You rebuild the select options repeatedly for each contact. If you created it once, then copied it to each contact that in itself would be more efficient.

Using a design where one component called another might be helpful in this context. If you could separate building the select options from the accounts & contacts you'd presumably find that very helpful towards performance.

Additionally, if you don't need to go back to the server for more products, you can use "setStorable" for any non-mutable functions that contain data which won't change (I doubt your products change and if your list of them doesn't, then this would be helpful to you). As a caution, do not use promises with storable actions!