The column.render callback runs too many times

The column.render callback runs too many times

DanSwitzer2DanSwitzer2 Posts: 21Questions: 4Answers: 0

While doing some refactoring of code to improve performance, I noticed an issue with column.render option.

When a function is defined to the column.render option, during table initialization the function is called way too many times for the display type. It runs more than once for each column and even when the deferRender: true is enabled, it runs at least once for each cell.

Take the following example:

$('#example').DataTable( {
  data: ExampleData,
  deferRender: true,
  columns: [
      { data: "name" },
      { data: "position" },
      { data: "office" },
      { data: "extn" },
      { data: "start_date", render: function (data, type, row, meta){
        if( type === "display" ){
            console.log("column " + meta.col);
        }
        if( type === "sort" ) return data.timestamp;
        
        return data.display;
      } },
      { data: "salary" }
  ]
} );

I would expect the console.log output to only get called 10 times on initialization (since the deferRender: true) option is on. However, it actually runs 68 times.

If I disable the deferRender option, it runs 114 times.

Here's a live example:
https://jsfiddle.net/dswitzer/539q35p8/1/

Why is this running so much? Shouldn't it only call the "display" type when actually rendering?

Replies

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Its caused by this function. DataTables is attempting to find the string that is the longest one in that column, and in order to find that information it needs to get the display data.

    You could add autoWidth set to false if you want to disable that behaviour (at the expense of the auto width calculations no longer being run): https://jsfiddle.net/539q35p8/2/ .

    Allan

  • DanSwitzer2DanSwitzer2 Posts: 21Questions: 4Answers: 0

    @allan,

    Thanks. That's interesting. You're right that turning that off, changes the behavior.

    However, we're using the Responsive plugin and I find that if the autoWidth option is set to false, then the table will not properly resize when either the window or parent container changes sizes.

    Is there a reason the results aren't at least cached?

    If the autoWidth is going to automatically force all the data to be rendered, then at least could the results be resused?

    I've got the deferRender set to true to avoid the cost of rendering all the rows, but the autoWidth attribute is essentially overwriting the benefit. However, when the nodes get added, their not able to use the values already calculated by the autoWidth option.

    Seems like if the cost of rendering is already incurred, then those results should be cached to avoid having to re-run the logic.

    Also, even with deferRender disabled when autoWidth is set to true the function ends up being called more than 3 times during initialization. Seems like if deferRender is false, then it shouldn't have to call the render function.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Is there a reason the results aren't at least cached?

    They are for filtering and sorting. But not for the display. It didn't seem worth the memory trade-off for a single additional access (the auto width calculation).

    Is your rendering function quite complex and taking a fair amount of time to run? In most cases the rendering function will be lightning fast and any optimisation there won't make much difference.

    Allan

  • DanSwitzer2DanSwitzer2 Posts: 21Questions: 4Answers: 0

    @allan

    It could be.

    The render function can use a templating engine to generate the display value. The templates are compiled, so the render actually just passes the results to a compiled template for rendering, but there could be a good amount of logic in there—depending on the template.

    The performance issue at play is that the render function is getting called at least twice for every column in the table at initialization. When I have a really large number of tables, it's definitely having some impact on performance. The more complicate the display template, the more potential hit there is.

    I can build in my own caching mechanism into the render, but I'm just trying to figure out if there's some ways autoWidth can be optimized. I'd leave the option disabled, but the tables don't resize properly without it (we need the responsive plugin, but the parent container can be resized by the user).

    I've got a really fast PC and with a relatively small table (13 columns, 382 rows) the initialization time via a local JS object still is somewhere between 580ms - 750ms). The autoWidth option seems to make the init time fluctuate anywhere between 10ms - 180ms. It obviously gets worse with more data.

    I'm getting ready to implement this on a dashboard that could have many tables on it, so I'm looking for any ways to reduce the performance.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Are you able to give me a link to the page show I can take a look at the trace?

    I suspect that the majority of the time with autoWidth enabled is not getting the display information, but rather calculating the column widths since that involves DOM interaction which is always slow.

    Allan

  • DanSwitzer2DanSwitzer2 Posts: 21Questions: 4Answers: 0

    @allan,

    Unfortunately, no.

    I'll have to see if I can figure out a way to get the responsive plugin working the way I need without setting the autoWidth option to enabled.

    When I don't disable this and the parent container width or page width changes, none of the columns are actually hidden.

  • DanSwitzer2DanSwitzer2 Posts: 21Questions: 4Answers: 0

    FYI - I tracked down the problem I was having with responsive tables and autoWidth. I had some code that was potentially altering the width of the column, which was attaching some behavior to the column-sizing event.

    The autoWidth was firing this event, which is why the code was working.

    I ended up having to update the code to attach to the window object's resize and orientationchange when the autoWidth option is not enabled.

    This has allowed me to disable the autoWidth option, which improves performance for me in a few other ways.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Awesome - nice investigation work :). Thanks for letting me know.

    Allan

This discussion has been closed.