3

I am developing a lightning component. In this component there is an attribute called allItems that contains an array of objects. Currently tested holding up to 600 objects.

However when I call a component.set with an updated array of objects, it takes a while to set/save the attribute and update the page visually.

Is there any way to improve speed/performance of component.set?

Code:

onItemMoved: function(component, event, helper)
{
    var titleid = event.getParam("titleid");
    var title = event.getParam("title");
    var maxSeats = event.getParam("maxSeats");
    var seatsInUse = event.getParam("seatsInUse");  
    var item = event.getParam("item"); //This is the item that was moved.
    var allGuestsList = component.get("v.allItems");
    console.log(item.index);

    //Searches guest list for matching guest. .
    //var actualGuest = allGuestsList.find(function(moving){return moving.id == item.id;});

        //Has the guest been moved to another table?
        if(item.status != title)
        {  
            //Does table have seats spare?
            if(seatsInUse>=maxSeats)
            {
                console.log(title, 'is full!\nMaximum guests for this table:', maxSeats);
            }
            else
            {
                item.status = title;
                item.statusid = titleid;

                allGuestsList[item.index] = item;
                component.set("v.allItems", allGuestsList);//This Line has slow performance past 200 objects being loaded.
            }

        }
}) 
  • please also share your component markup code so we can see how you are rendering all this data – Itai Shmida Oct 21 '18 at 8:42
0

How did you conclude that component.set() is the culprit? Also, are you viewing all 600 records in one-go on a page? If so, I have a feeling that this is more of a display issue than an issue with component.set() itself. You can determine that by measuring the time taken for component.set() to execute like so:

.
.
.
    var t0 = performance.now();
    component.set("v.allItems", allGuestsList);//This Line has slow performance past 200 objects being loaded.
    var t1 = performance.now();
    console.log("------------> component.set took " + (t1 - t0) + " milliseconds to execute.")
.
.

If the time reported is reasonably small, you know what I am talking about. It could be the actual time taken to render so much data on the page. To prove/test it, there are a few things you could try:

  1. Reduce the number of columns (not rows) being displayed on the screen (assuming this is a table).
  2. Keep ALL 600 records in v.allItems, but only render a few lines as opposed to ALL using an aura:if or something similar in your markup.
  3. Use direct values like <td>{!item.Name}</td> as opposed to lightning:* or ui:* base components like <td><lightning:formattedText value="{!item.Name}"/></td>

and see if the performance improves. If it does, you might have to consider implementing pagination.

  • 1
    I confirmed that component.set() is the cause since I comment out component.set() the lag is gone, but it no longer updates the component visually until I refresh it from the database again, which also takes some time since a refresh calls my doInit which sets the components with data gathered from soql. – Alexander Atkinsoon Oct 12 '18 at 7:21
0

Hi Alexander Atkinsoon and anyone else who experiences this issue. This may or may not solve your problem (unless onItemMoved is called repeatedly), but it may help others.

I can confirm that component.set is slow - especially with rapidly repeated calls to the same variable - even if the data set is small. This is probably due to the lightning data service wrapping the data - so, naturally this will be slower.

Some use cases however don't have a simple work-around (e.g. when responding to a number of rapid events).

Background

My issue came in when building a declarative, filterable, and sortable data table component. To be sortable (and have row selection capabilities), the outer table component needed to know the unique IDs of each row. As the rows are declaratively defined - this data had to be provided to the table by each inner row component upon its initialization. This was done by capturing an custom init event with the required data.

Long story short, I found that filtering the data in the component for just 100 rows took around 10 seconds - causing the browser to show a slow/unresponsive script message.

Eventually, I found that it was not the row component creation, event firing, or rendering that was the problem; it was a repeated component.set call.

This call was within the outer table component after each row had initialized (after filtering). The component.set incremented a stored array that held each row's unique ID such that the table could handle row selections. By removing this call, the filtering time went from ~10s to ~0.3s.

So, an alternative:

Instead of running component.set each time a row was rendered, I cached the values in the table component's helper class and ran the component.set call at the end.

For example:

Table Helper class

({
    valueCache : [],

    //This is called to redraw the table rows to represent new or filtered data
    startRowRedraw : function(component, helper) {
        var globalId = component.getGlobalId();
        valueCache[globalId] = [];

        //Trigger row redraw here
        doIt();
        //Redraw has finished

        component.set("v.rowIds", valueCache[globalId]);
        valueCache[globalId] = [];
    },

    //Fired by handling to row init event
    //This is the new ~0.3s version.
    handleRowInit_NEW : function(component, event, helper) {
        //Fires after each row has been added to the table
        var row = event.getSource();
        helper.valueCache[component.getGlobalId()].push(row.get("v.uniqueId"));
    },

    //No longer fired by handling to row init event
    //This is the old ~10s version of the row init handler
    handleRowInit_OLD : function(component, event, helper) {
        //Fires after each row has been added to the table
        var row = event.getSource();
        var rowIds = component.get("v.rowIds");
        rowIds.push(row.get("v.uniqueId"));
        component.set("v.rowIds", rowIds);
    }
});

Note that the valueCache array is referenced by the component's global ID. That is because this variable will be shared by every instance of the table component, as helper classes are shared.

I hope this helps someone in a similar situation!

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.