My large table IE fix

My large table IE fix

jcrossjcross Posts: 3Questions: 0Answers: 0
edited July 2010 in General
Had a 900+ row html table that was taking forever to load up only in IE. Doing searches here, Google, & StackOverflow , I finally ascertained that the problem was in the fnGatherData function. Specifically the following line (2327 in 1.7 beta 5):

[code]aLocalData[jInner] = $.trim(nTds[j].innerHTML);[/code]

IE apparently has performance issues with .innerHTML. I replaced the above line with the following:

[code]aLocalData[jInner] = $(nTds[j]).text().trim();[/code]

Now I have no performance issues in IE with my large table.

Replies

  • allanallan Posts: 61,743Questions: 1Answers: 10,111 Site admin
    Hi jcross,

    Thanks very much for this - it's an important topic optimisation! The one problem with your function here is that it will not read any HTML which might be within the cell. jQuery's text function will read the nodeValue for text and cdata node types only, it will not get the tag names, attributes or anything like that which innerHTML will.

    So while this optimisation is good and will probably be suitable in the majority of cases, it doesn't cover all of them. One option which I'll look at might be to query the TD nodes childNodes DOM array. If it is == 1 and of type text or cdata then read the nodeValue, otherwise read the innerHTML. This might be a very nice little change... I'll try it out and profile it. Thanks for the heads up :-)

    Regards,
    Allan
  • allanallan Posts: 61,743Questions: 1Answers: 10,111 Site admin
    Hi jcross,

    I've just tried the following code in place of the line you identified:

    [code]
    childNodes = nTds[j].childNodes;
    if ( childNodes.length == 1 &&
    (childNodes[0].nodeType === 3 || childNodes[0].nodeType === 4) )
    {
    aLocalData[jInner] = $.trim(childNodes[0].nodeValue);
    }
    else
    {
    aLocalData[jInner] = $.trim(nTds[j].innerHTML);
    }
    [/code]
    With 2000 rows (and 9 columns) this shows virtually no difference in IE8 (possibly slightly slower) and definitely slightly slower in Safari interestingly enough.

    Equally I've just tried the change you gave and don't notice any significant difference. Do you see an obvious difference when the change is made?

    Thanks,
    Allan
  • sd_zuosd_zuo Posts: 78Questions: 1Answers: 0
    edited July 2010
    How about using the following to avoid bothering the childNodes collection:
    [code]
    var cell = nTds[j];
    var fc = cell.firstChild;
    if (fc == cell.lastChild && (fc.nodeType === 3 || fc.nodeType === 4)) {
    aLocalData[jInner] = $.trim(fc.nodeValue);
    }
    else ...
    [/code]
  • jcrossjcross Posts: 3Questions: 0Answers: 0
    edited July 2010
    Created three test pages. 956 rows, 8 columns:

    original 1.7 beta 5: http://millville.sps.edu/testDataTablesOriginal.aspx
    allan mod: http://millville.sps.edu/testDataTablesAllan.aspx
    jcross mod: http://millville.sps.edu/testDataTablesJCross.aspx

    approx. load times in IE 8

    orig - 30 sec.
    allan - 15 sec.
    jcross - 3 sec.
  • allanallan Posts: 61,743Questions: 1Answers: 10,111 Site admin
    Hi jcross,

    Thanks for posting these! I just tried out the example of your own modification but IE is giving me an error on the line 'debugger;'. Safari appears to just ignore it for whatever reason.

    Thanks,
    Allan
  • jcrossjcross Posts: 3Questions: 0Answers: 0
    edited July 2010
    Got rid of the debugger line in each link's js files
  • gutzoftergutzofter Posts: 58Questions: 0Answers: 0
    If this is true then I should be able to get rid of a lot of server side processing. This is specifically an issue that I had with IE. My table only had ~= 400 rows. Good job!
  • allanallan Posts: 61,743Questions: 1Answers: 10,111 Site admin
    edited July 2010
    I think I know what is happening here, and it's actually something that we've come across in the forum before: http://datatables.net/forums/comments.php?DiscussionID=1389#Item_8 . csulok's reply sums my my feelings!

    Basically innerHTML on an element which is hidden in IE is _VERY_ slow. Presumably this is an "optimisation" in IE, which is being used unintentionally in this case. I've just tried this on my performance testing table and it took 260s to initialise in IE with the table hidden, but only 27s with it displayed. The optimisation suggested by jcross helps even more, again basically due to the IE internals.

    So I'm sorry to say that this is not a 'silver bullet' to cure problems with rendering performance in IE. The fact is that the Javascript engine in IE8 and before is just very slow, and DataTables is doing some heavy DOM access.

    I'm going to look some more at including either the childnodes or firstChild approach when there is only a text node, since there is no real performance impact of doing this, but at a significant benefit under these circumstances, but this isn't going to solve all ills I'm afraid.

    Edit: Actually, at this time I'm not going to include the ability to read the nodeValue, rather than the innerHTML. The reason for this is the performance wise (when the table is visible) there is no noticeable difference, however they behave slightly differently. Specifically when reading HTML entities innerHTML will give the entity, while the nodeValue will give the rendered display character. This will upset other parts of DataTables, which is why I don't want to do this just now.

    All in all, basically its an issue with the IE JS engine when dealing with hidden elements. Of course there is the work around suggested by jcross, and this will work, but is not suitable for inclusion in the distribution at this time. However, anyone who meets the requirements needed for this workaround to be suitable can of course use it (hooray open source :-) ). Wonder if this is still an issue in IE9...

    Regards,
    Allan
  • sd_zuosd_zuo Posts: 78Questions: 1Answers: 0
    edited July 2010
    Hi there,

    I did not dig deep in the source code of jcross's links. But I think that jcross's examples are too complicate to debug and test against the speed improvement. I am now using jQuery+DataTables within my intranet, with the following configuration:
    [code]
    $("#Results").css("width", "100%").dataTable({
    "aaData": d,
    "bJQueryUI": true, "sPaginationType": "full_numbers", "sDom": '<"H"lrp>t<"F"if>',
    "bAutoWidth": false, "aaSorting": [],
    "aoColumns": tc, // an array of 14 columns' configuration
    "fnRowCallback": function(nRow, aData, iDisplayIndex) {
    $(nRow).attr("title", "id?".concat(aData[0], "\nmemo?", aData[13]));
    var c = $("td:eq(3)", nRow).get(0);
    if(c.firstChild.nodeType == 3){
    c.appendChild(document.createElement("a")).href = "javascript:jump(" + aData[4] + ");";
    c.lastChild.appendChild(document.createTextNode(c.firstChild.nodeValue));
    c.removeChild(c.firstChild);
    }
    return nRow;
    },
    "fnInitComplete": function() {
    $("#Results_filter").css("width", "30%");
    }
    });
    [/code]
    Result: (I watched the Task Manager and clocked the CPU time used to render the page, so network latency should be eliminated)
    1, Above configuration with DataTables 1.7 beta 5 unmodified:
    1.1, Initializing the table with 4000 rows of JSON records (the d variable): around 20 seconds.
    1.2, Initializing the table with 1000 rows: 5 seconds.
    2, jcross's example (around 900 rows)
    2.1, 1.7 b5: 57 seconds around.
    2.2, Allan's: 19 seconds around.
    2.3, jcross's: 4 seconds around.

    According to the above data, the result of 1.2 is evidently smaller than the result of 2.1 or 2.2, but the amount of data is about the same. Hereby, I suspect that there might be something else wrong with jcross's examples besides the innerHTML issue.

    I initially use server side processing to render those 4000 rows into a HTML table and then apply DataTables onto it. The render speed is unacceptably downright slow. IE sucks loading large HTML tables alone, further more, CSS style and JavaScript processing also affects the rendering speed significantly.

    Afterward, I switched to use server side processing to generate a JSON variable, and used DataTables to load it into an empty table. To my surprise, the loading time was greatly reduced.

    I think large table rendering should be switched from HTML table + DataTables to JSON data + DataTables, which will improve the performance by at least 400% since IE does not have to parse and render the HTML table.
    And I also found that making all table rows initially invisible (display: none) and then making small amount of them visible after applying DataTables onto that table can reduce the rendering time.
  • allanallan Posts: 61,743Questions: 1Answers: 10,111 Site admin
    Hi sd_zuo,

    Thanks for the extra information!

    When optimising the DataTables data source for speed, it is important to consider the overheads involved in each action:

    - DOM source: reading the information from the DOM - which can be horribly slow, particularly in IE
    - Ajax source: the time needed for the XHR and then creating the DOM nodes needed for all records
    - Server-side processing: the time needed for the XHR, and then creating the DOM nodes for the current display only

    Server-side processing's response time should be fairly flat. The other two will depend directly on how much data there is, and there will come a point when server-side processing is the way to go.

    The key thing with jcross's example is that the table is hidden initially, which triggers an IE issue that will absolutely kill innerHTML performance. That's why it is running so horribly slowly, and why noveValue helps so much.

    Allan
  • _andreas__andreas_ Posts: 4Questions: 0Answers: 0
    @sd_zuo
    [code]var cell = nTds[j];
    var fc = cell.firstChild;
    if (fc == cell.lastChild && (fc.nodeType === 3 || fc.nodeType === 4)) {
    aLocalData[jInner] = $.trim(fc.nodeValue);
    }
    else ...
    [/code]

    Your code works, but you have to add something like (fc === null) for empty table cells.

    Andreas
  • fthomasfthomas Posts: 8Questions: 0Answers: 0
    edited April 2011
    I'd really like to reopen this issue. I have a table that is pulling around 3,700 records and I'm finding no matter what I do to optimize as per this thread in both FF and IE my performance is hovering around 40 seconds. No changes no matter what. I'm I out to lunch on this one? I am running the latest and greatest downloaded today(27apr11).

    To be honest, I'm starting to think that this a server side processing task, but I'm going to need some heavy hand holding to move in that direction.

    Thanks!

    Frank
  • allanallan Posts: 61,743Questions: 1Answers: 10,111 Site admin
    Hi Frank,

    You might be interested in this thread, which discusses a speed up for IE in 1.8: http://datatables.net/forums/comments.php?DiscussionID=4739

    Allan
This discussion has been closed.