14

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?
  • Hi Med, welcome to SFSE! Show us a little bit more of your Markup and how you have defined the attributes you are using. Have you tried to replace lightning:select by something else, e.g. ui:inputSelect? – Uwe Heim Sep 16 '17 at 14:23
  • 1
    What happens, if you render just plain-text {!product.Name} in the innermost 3rd iteration? Any difference? I mean without the select and the options at all? Reason: rule out the select as bottleneck. – Uwe Heim Sep 16 '17 at 14:27
  • The select does not bottleneck the aura-iteration, it is the iteration that bottlenecks. – Med Douici Sep 18 '17 at 13:08
  • @UweHeim Did you ever find a workaround or at least learn what the root cause for this is? I am suffering from it very badly. – Robert Sösemann Nov 8 '17 at 15:54
  • 1
    @RobertSösemann my workaround is unfortunately an anti-pattern: out of desperation, I dropped all the Salesforce-UI elements and now I'm creating my own DOM-elements with jQuery and Javascript. The mapping is done by javascript. It's super fast now. For complex UIs, I found the native Salesforce widgets to be lightning slow and was not able to speed them up. Especially lots of simple picklists values... the answer below was not helpful. – Uwe Heim Nov 8 '17 at 17:41
0

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!

  • Hi crmprogdev, the OP has already the subselect you are showing. But he needs three things: accounts, contacts and products. And products are not related, he is using here all products on any contact. I think it's kind of a product-preference mass-selector for lots of contacts nested in accounts and therefore 3 nested iterations. Also he said it's not the apex causing the issue. – Uwe Heim Sep 16 '17 at 14:15
  • And you are right: it's without the WHERE part. The childrelationship name "Contatcs" is doing the magic. – Uwe Heim Sep 16 '17 at 14:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.