Optimizing JQuery DataTables Performance

I have spent the past several weeks working with the excellent DataTables plugin for JQuery. I’ve actually been quite impressed by the plugin’s speed and flexibility, even when working with large sets of data.

My situation might be a bit weird, but I certainly don’t think it’s unreasonable. One of my larger datasets has around 50 columns and a bit over 1,000 rows. I need the user to be able to put the columns in any order they want, while also being able to Show / Hide all of the columns. Pagination is enabled.

While developing, I ran across a few pitfalls that may not be entirely obvious at first. By avoiding these, I easily cut the time to initialize my large DataTables instance by a factor of 10. I’m documenting them here both for my own future reference, and in case anybody else runs into similar issues.

Populating the Table

When I first began working with DataTables, I was generating a plain HTML table on the server, inserting it into the DOM, and then converting it to a DataTable. While this certainly produced the desired result, it did not produce the desired result in a reasonable amount of time. Even worse, the entire tab would freeze as the table took several seconds to initialize.

The first step in mitigating this turned out to be passing in JSON at initialization instead of straight-up HTML. From what I can tell, when you pass in HTML, DataTables has to parse the entire dataset to javascript objects to save into its internal model of the table, which can be quite time consuming. If you’re passing in JSON, on the other hand, it appears to be a much speedier process.

However, DataTables does have to convert this JSON to HTML at some point, to display to the user. Luckily, the plugin offers an option to defer the rendering of this HTML until it is needed, ensuring that you don’t have to wait too long as the table initializes:

"bProcessing": true,
"bDeferRender": true,

// Rows and column headers stored in a "data" object:
"aaData": data.aaData,
"aoColumns": data.aoColumns

Note that I’m not using the DataTables built-in Ajax loader. Unfortunately, the loader does not currently accept the column headers as part of the response from the server, and I was determined to send both those headers and the actual data in a single response. So I’m rolling my own Ajax call with JQuery, and then just passing in the result.

This optimization is mentioned in the DataTables Documentation as well:

The method you are using for loading the data will typically have the most significant impact on performance.

Programmatically Reordering Columns

Part of the application that I’m developing requires saving information about the state of the screen as a user leaves and restoring it as they come back. Naturally, this includes the order and visibility of the columns in the DataTable. Other parts of the application require that all of the data be in the actual DataTable at all times, even if most of it is invisible.

When the page loads, I request a bit of information about the page’s state from the server. As part of its response, it passes a list of visible columns and their order:

var columns = ["Python", "Javascript", "Perl", "Ruby", "C"]

Note, however, that “C++”, “Pascal”, and “Java” do not appear in that list, so those columns shouldn’t be visible.

To do this, I use the column reorder extra and move all of the visible columns to the left and the invisible columns to the right.

// Goes through and puts all of the visible columns in the correct
// order on the left, and the invisible columns on the right.
for(i = 0; i < columns.length; i++) { // "indexNums" maps from column title to the index of // the column in the table var from = indexNums[columns[i]]; var to = i;
if(from !== to) {
dataTable.fnColReorder(from, to);

// Updates our cache of column order
var min = (to < from)? to : from; var max = (to > from)? to : from;
for(j = min; j <= max; j++) { indexNums[oSettings.aoColumns[j].sTitle] = j; } }}[/code]I then go through and set the visibility on each column individually, keeping in mind that all of the visible columns are all the way to the left, and all of the invisible columns are all the way to the right.[code lang="javascript"]// Hide the columns that aren't mentioned in the column listfor(i = 0; i < oSettings.aoColumns.length; i++) { dataTable.fnSetColumnVis(i, (i < columns.length), false);}[/code]Note the third argument to that function call, however. That's the truly important one. As stated in the API documentation, the third (optional) argument determines whether or not to redraw the table. It defaults to true.

However, if you're changing the visibility of 50 columns all within a very short period of time, redrawing the table every time can become quite expensive. In my testcase, on a fairly modern computer running the latest Chrome, it took around 6 seconds to change the visibility of all 50 or so columns. Disabling the redraw brought it down to a few milliseconds.

The final piece was to instruct DataTables to recalculate the widths of each column. This would normally be done while setting column visibility, but is disabled when you tell it not to redraw the table. Luckily, it's simple:

[code lang="javascript"]dataTable.fnAdjustColumnSizing();

Anybody else have any other tips for improving DataTables performance?

Eric Jeney is a Java aficionado with a number of projects under his belt. He enjoys programming for the web, and writing about his experiences. He currently studies Computer Science at the University of Maryland.

View all posts by Eric →