The column.render callback runs too many times
The column.render callback runs too many times
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
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
autoWidthset tofalseif you want to disable that behaviour (at the expense of the auto width calculations no longer being run): https://jsfiddle.net/539q35p8/2/ .Allan
@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
autoWidthoption is set tofalse, 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
autoWidthis going to automatically force all the data to be rendered, then at least could the results be resused?I've got the
deferRenderset totrueto avoid the cost of rendering all the rows, but theautoWidthattribute is essentially overwriting the benefit. However, when the nodes get added, their not able to use the values already calculated by theautoWidthoption.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
deferRenderdisabled whenautoWidthis set totruethe function ends up being called more than 3 times during initialization. Seems like ifdeferRenderis false, then it shouldn't have to call the render function.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
@allan
It could be.
The render function can use a templating engine to generate the
displayvalue. 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
renderfunction 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
autoWidthcan 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
autoWidthoption 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.
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
@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
autoWidthoption to enabled.When I don't disable this and the parent container width or page width changes, none of the columns are actually hidden.
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 thecolumn-sizingevent.The
autoWidthwas firing this event, which is why the code was working.I ended up having to update the code to attach to the
windowobject'sresizeandorientationchangewhen theautoWidthoption is not enabled.This has allowed me to disable the
autoWidthoption, which improves performance for me in a few other ways.Awesome - nice investigation work
. Thanks for letting me know.
Allan