Scroller#_fnDrawCallback() forces browsers layout twice, but only needs to do it once with a very simple change. It saves about 30ms for me in IE, which is a lot if you're filtering rows as the user types.
"_fnDrawCallback": function () { var that = this, // NOTE: scrollTop forces browser layout iScrollTop = this.dom.scroller.scrollTop, iScrollBottom = iScrollTop + this.s.viewportHeight, // CHANGE: Calculate iTableHeight here while the layout is still valid iTableHeight = $(this.s.dt.nTable).height(); /* Set the height of the scrolling forcer to be suitable for the number of rows * in this draw */ this.dom.force.style.height = (this.s.rowHeight * this.s.dt.fnRecordsDisplay())+"px"; /* Calculate the position that the top of the table should be at */ var iTableTop = (this.s.rowHeight*this.s.dt._iDisplayStart); if ( this.s.dt._iDisplayStart === 0 ) { iTableTop = 0; } else if ( this.s.dt._iDisplayStart === this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength ) { iTableTop = this.s.rowHeight * this.s.dt._iDisplayStart; } this.dom.table.style.top = iTableTop+"px"; /* Cache some information for the scroller */ this.s.tableTop = iTableTop; // CHANGE: Use the precalculated iTableHeight // this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop; this.s.tableBottom = iTableHeight + this.s.tableTop; this.s.redrawTop = iScrollTop - ( (iScrollTop - this.s.tableTop) * this.s.boundaryScale ); this.s.redrawBottom = iScrollTop + ( (this.s.tableBottom - iScrollBottom) * this.s.boundaryScale ); if ( this.s.trace ) { console.log( "Table redraw. Table top: "+iTableTop+"px "+ "Table bottom: "+this.s.tableBottom+" "+ "Scroll boundary top: "+this.s.redrawTop+" "+ "Scroll boundary bottom: "+this.s.redrawBottom+" "+ "Rows drawn: "+this.s.dt._iDisplayLength); } /* Because of the order of the DT callbacks, the info update will * take precidence over the one we want here. So a 'thread' break is * needed */ setTimeout( function () { that._fnInfo.call( that ); }, 0 ); /* Restore the scrolling position that was saved by DataTable's state saving * Note that this is done on the second draw when data is Ajax sourced, and the * first draw when DOM soured */ if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null && typeof this.s.dt.oLoadedState.iScroller != 'undefined' ) { if ( (this.s.dt.sAjaxSource !== null && this.s.dt.iDraw == 2) || (this.s.dt.sAjaxSource === null && this.s.dt.iDraw == 1) ) { setTimeout( function () { $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller ); that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (that.s.viewportHeight/2); }, 0 ); } } },