Avoiding a Performance Gotcha with Jquery Datatables and Deep Objects

tl;dr

If you are using the "data" attribute of jquery Datatables, it does a deep copy on all settings (which includes the "data" attribute), which can cause a significant performance hit if your "data" array contains complicated objects.

One solution to this is to use the "render" attribute to define a function that creates the html for the table element, and use an array of the ids for the objects as the "data" object.

I have been using jquery datatables to show lists of people in a family tree visualization tool I have been playing with (and I think datatables is awesome, btw). As the number of people in the tree can be pretty big, I wanted to use the deferRender property coupled with scroller.js to provide a fast "infinite" scroll that will render rows only when needed.

In setting this up, I was seeing fairly poor performance, and determined that the issue was that the datatables initialization function will (for some reason) do a deep copy of the settings passed in (here is link to line in the source code). The "data" passed in for the datatables is part of this "settings" object.

In my case, the objects in the array had multiple levels, and the deep copy was causing a huge performance hit before anything was even done with trying to render the table.

The solution (for now) was to use an array of simple objects that basically just contained the id's for the objects - then when the render function is called, the object itself is looked up from the id. The improvement in performance was striking, imo.

I'm not sure if this is really a bug or not or anything - this might be an edge case that doesn't come up very often: I've a largish number of (deep-ish) javascript objects already in hand and want to show some aspects of them in a table.

Anyway, relevant sample code is below.



$divEl.append('<table cellspacing="0" ' +
                        'class="detailTable table-striped ' +
                              ' table table-bordered table-hover table-condensed">' +
                   '<thead></thead><tbody></tbody></table>');

var $dt = $divEl.find('.detailTable');

//allPeopleByIdsArray = [{'id':id1}, {'id': id2},...];

that.theTable = $dt.dataTable({
                   'data': allPeopleIdsArray,
                   'deferRender': true,
                   ... other initialization properties...
                   'columns': [
                    {
                     'title': 'Name',
                     'data': 'id',
                     'render': 
                        function (data, type, full, meta) {
                          var p = allPeopleById[data],
                              sLink = p.getGoogleLinkIfApplicable();
                              s = '<a href="' + sLink + '">' + 
                                       p.getNameLastFirst() + '</a>';
                          return s;
                      },
                     'className': 'detail-person-name'
                    }
                  });

Popular Posts