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
autoWidth
set tofalse
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
@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 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
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 totrue
to avoid the cost of rendering all the rows, but theautoWidth
attribute is essentially overwriting the benefit. However, when the nodes get added, their not able to use the values already calculated by theautoWidth
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 whenautoWidth
is set totrue
the function ends up being called more than 3 times during initialization. Seems like ifdeferRender
is 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
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.
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
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.
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-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'sresize
andorientationchange
when theautoWidth
option is not enabled.This has allowed me to disable the
autoWidth
option, which improves performance for me in a few other ways.Awesome - nice investigation work . Thanks for letting me know.
Allan