Table slow in FF, fast in Chrome

Table slow in FF, fast in Chrome

edited February 2012 in DataTables 1.9 Posts: 164
I create a table using:

$tableElement.dataTable( { "sScrollY": plugin.settings.tableHeight+"px", "sScrollX": "100%", "aaData": tableData, "bStateSave": true, "bSortClasses": false, "bDeferRender": true, "bAutoWidth": false, "sPaginationType": "full_numbers", "sDom": 'z<"H"<"#datatable_'+plugin.settings.id+'_menu"f>r>tSpi',//typeArray, "aoColumns": getColumnConfigArray(), "bLengthChange": false, "fnRowCallback": function( nRow, aData ) { /* add primary key value to row, so we can easily get it when the row is selected */ jQuery(nRow).data('dataGrid.primaryKeyValue', aData[plugin.globals.primaryKeyIndex]); return nRow; }, "fnStateLoadCallback": function ( oSettings, oData ) { /* get state of column search inputs, used to set the values */ columnSearchInputState = oData.aaSearchCols; return true; }, "fnDrawCallback": function( oSettings ) { _onTableRedraw(oSettings); console.log('_onTableRedraw'); }, "fnInitComplete": function() { /** * Keep reference to the datatable object **/ plugin.dataTableObject = $tableElement.dataTable(); /*new FixedColumns( plugin.dataTableObject );*/ /** * Call _onWindowResize, because it will set the wrapper with **/ _onWindowResize(); /** * Show item after init, see fireGridAndFormJS.php **/ if(typeof(tableid) != "undefined") { this.fnFilter( tableid, 0 ); selectRowById(plugin.settings.id); //this.oScroller.fnScrollToRow(0); } /** * Filters rows, as stored in in cookie **/ var oSettings = $tableElement.dataTable().fnSettings(); for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ ){ if(oSettings.aoPreSearchCols[i].sSearch.length>0) { $tableElement.children("tfoot").find("input").eq(i).val(oSettings.aoPreSearchCols[i].sSearch); } } /** * Filter columns, as stored in cookie **/ for ( var i=0 ; i<oSettings.aoColumns.length ; i++ ){ if(oSettings.aoColumns[i].bVisible == false) { $("#columnfilter input").eq(i).removeAttr("checked"); } } }, "bJQueryUI": true } );
This works fine, but in FF the table (1500 rowsx 21 columns) is really slow. In Chrome it is fast. Is there some CSS/Javascript tweak needed?

Replies

  • Posts: 22,706
    How slow is really slow? I don't see anything in the above that should slow Firefox down badly. Are you able to give me a link so I can profile it?

    You could always show a message suggesting the user upgrade to Chrome ;-)
    (I jest...)

    Allan
  • Dear Allan,

    Slow is that it takes +/- 5-10 seconds for every table redraw event. So when search, each letter typed will create a non-responsive FF for 5-10.

    On http://pkedu.wmmrc.nl/firebug_slow_ff.png you will find the screenshot of the Firebug profile when a table redraw event is triggered. Its in Dutch, but the words are not to difficult to translate:

    Functie = function
    Aanroepen = calls
    Procent = Percent
    Eigen tijd = own time
    Tijd = time
    Gem = Avg
    Bestand = File

    What amazes me is the fact that one table redraw causes 254.627 function calls!

    I hope this give you a clue. Making a public demo is quite difficult right now, but if needed, I can provide you with that.
  • Posts: 22,706
    Hmm - that does seem rather a lot! Could you run your table through the DataTables debugger ( http://debug.datatables.net ) so I can see what the configuration is please?

    Thanks,
    Allan
  • Mmm.... running the debugger causes FF to crash...

    It looks like the problem is really in the search function, which is called a lot of times...
  • Posts: 22,706
    Bummer - is it a large table?

    What calls are you using to redraw the table? Is it server-side processing, client-side Ajax, deferred rendering etc?

    Allan
  • edited February 2012 Posts: 164
    I have added something to _fnGetCellData:

    function _fnGetCellData( oSettings, iRow, iCol, sSpecific ) { console.log(iredrawcount++); console.trace(); ... }
    When I add 1 letter to the search input field, this function is called 2 times for each cell.

    So: with 37 columns:

    and 1 row: 2x37x1 = 74 calls
    and 2 rows 2x37x2 = 148 calls
    etc.

    To me this seems... not very scalable. There are two types of traces:


    Trace 1:
    _fnGetCellData(oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, iRow=0, iCol=3, sSpecific="filter")jquery...bles.js (line 734) _fnGetRowData(oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, iRow=0, sSpecific="filter")jquery...bles.js (line 716) _fnBuildSearchArray (oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, iMaster=1)jquery...bles.js (line 2216) _fnFilter(oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, sInput="a", iForce=0, bRegex=false, bSmart=true, bCaseInsensitive=true)jquery...bles.js (line 2162) _fnFilterComplete (oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, oInput=Object { sSearch="a", bRegex=false, bSmart=true, meer...}, iForce=undefined)jquery...bles.js (line 2021) (?)(e=Object { originalEvent=Event keyup, type="keyup", timeStamp=1330346617428, meer...})jquery...bles.js (line 1978) handle(a=Object { originalEvent=Event keyup, type="keyup", timeStamp=1330346617428, meer...})jquery....min.js (line 63) add()jquery....min.js (line 57)
    Trace 2:
    _fnGetCellData(oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, iRow=1, iCol=0, sSpecific="filter")jquery...bles.js (line 734) _fnGetRowData(oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, iRow=1, sSpecific="filter")jquery...bles.js (line 716) _fnBuildSearchArray (oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, iMaster=0)jquery...bles.js (line 2216) _fnFilterComplete (oSettings=Object { oFeatures={...}, oScroll={...}, oLanguage={...}, meer...}, oInput=Object { sSearch="a", bRegex=false, bSmart=true, meer...}, iForce=undefined)jquery...bles.js (line 2049) (?)(e=Object { originalEvent=Event keyup, type="keyup", timeStamp=1330345762917, meer...})jquery...bles.js (line 1978) handle(a=Object { originalEvent=Event keyup, type="keyup", timeStamp=1330345762917, meer...})jquery....min.js (line 63) add()jquery....min.js (line 57)
    What happens is (I put it in pseudo code):

    for (iRow=numberOfRows-1; iRow>=0; iRow--) { for (iCol = 0 ; iCol < numberOfCols ; iCol++ ) { _fnGetCellData called according to Trace 1 } } fnDrawCallback called for (iRow=numberOfRows-1; iRow>=0; iRow--) { for (iCol = 0 ; iCol < numberOfCols ; iCol++ ) { _fnGetCellData called according to Trace 2 } }
  • edited February 2012 Posts: 22,706
    _fnGetCellData is DataTables' method of getting the data for a cell (funnily enough :-) ) - it allows abstraction of the data types to allow mDataProp to do what it does. It does mean that there is a function call every time there data is requested (which is why it would be called twice or more in a full draw). However, if this wasn't done, then it would still need an array look up (less overhead than a function call sure, but still a finite time) and be hugely less flexible (a la DataTables 1.7- in fact).

    So, as I mentioned, perhaps you can give me some details about how you are actually using DataTables so I can see where it might be possible to improve things.

    As an example of how draw times should be: http://datatables.net/release-datatables/extras/Scroller/large_js_source.html . It takes a little while to load the page, a large part of which is due to the array creation, however if you click a column header, you should see how fast a sort and redraw occurs.

    Allan
  • edited February 2012 Posts: 164
    Dear Allan,

    Thanks, I will try to fabricate an online sample.

    About http://datatables.net/release-datatables/extras/Scroller/large_js_source.html: did you also try to have more columns than rows? E.g. 30 columns and 1500 rows? This should not make a difference, but you never know :)

    Koos
  • edited February 2012 Posts: 164
    One question (or maybe an improvement :): Would it be a good idea to set a timeout on the search input? Now it will perform 5 full searches when I search for '12345':

    1
    12
    123
    1234
    12345

    If there would be a timeout of e.g. 200 ms before search starts (and reset by each keyup), it would only search one, for 12345
  • edited February 2012 Posts: 164
    Hi Allan,

    This is the weirdest thing I have seen for years. I wanted to make a test for you:

    1) I saved my webpage in FF containing the DataTable using 'File' -> 'Save page as' to test.html
    2) In test.html, I replaced the innerHTML of the <body> with the original HTML of my webpage (as the method in point 1 will save the [i]rendered[/i] HTML, not the original HTML).

    Guess what?

    test.html is almost as fast as Google Chrome!

    I have absolutely no clue of how this is possible.
  • Posts: 22,706
    ould it be a good idea to set a timeout on the search input? Now it will perform 5 full searches when I search for '12345':

    Use this plug-in: http://datatables.net/plug-ins/api#fnSetFilteringDelay

    I have absolutely no clue of how this is possible.

    Lol - very odd! I'm afraid I don't have any suggestions on what might be happening there :-(. It sounds like it should be exactly the same. Might you have cache disabled in Firefox or something?

    Allan
  • I know you've no doubt ruled this out already, but I've noticed today that FF is running really slowly whilst FireBug is enabled.

    This is when trying to display a dataTable with approximately 60 rows and 41 columns (with a lot of fnRender calls). Chrome's developer tools don't seem to be slowed down at all.
  • Posts: 22,706
    Good point - I keep forgetting how ugh of a drag Firebug adds to drag (I do love the Webkit dev tools :-) ). I wonder if the built in Firefox dev tools will build up to that kind of functionality in future as well.

    Thanks for noting this!

    Allan
  • edited March 2012 Posts: 164
    Thanks! When I remove FireBug, FF is fast again. Weird, because I turn FB off in both cases, but apparantly that's not enough.

    Would it be an idea to have this somewhere on the website (if not already the case?). Do not use FireBug with large tables?
  • Posts: 1
    The fnSetFilteringDelay plugin solved my problem which was the same as koosvdkolk mentioned. By default, the datatable does large pauses as the thread blocks subsequent requests as the user types in the search field.

    Most other widgets like this include the type ahead delay (via setTimeout and cancelling pending requests within a msec range) as a default. Is there a reason datatables.net doesn't? I can't see a reason you wouldn't want this, as it would give a much better user experience by default.

    FYI this isn't related to big tables... we noticed this issue when testing on a table with 1 row in it.
  • Posts: 22,706
    @koosvdkolk: I've added a note to the 'speed' FAQ: http://datatables.net/faqs#speed

    @rpocklin:

    Is there a reason datatables.net doesn't?

    Yes, typically most tables that are used with DataTables are client-side and typically < 500 rows (at least in my experience (the new debugger might be able to confirm that as time goes by and information is gathered). With such tables, the client-side processing of key press filtering is extremely responsive, providing, in this case, a much better user experience. Of course this doesn't hold true in all cases, and that's what the plug-ins are for :-) (for example where server-side processing is enabled - are you using SSP?).

    The plug-ins can and should be used where appropriate, but this isn't turn in all of cases and therefore adding it to the DataTables core would be a bad thing - that's how library bloat occurs and I'm going to harsh on accepting code (from myself in particular!) into the core that adds extra weight to it. I'd much rather keep DataTables to a sensible size (currently 68K) than just adding the odd feature here and there and ending up with a 1/4MB Javascript file!

    Allan
This discussion has been closed.