-
Notifications
You must be signed in to change notification settings - Fork 754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
appendToTable is very slow in IE9+...any way to speed up the script? #72
Comments
I'm not sure if you're using the latest version but I recently changed both the main tablesorter plugin and the pager plugin to start using document fragments to speed up the table rendering process. So using If you are using the latest version, then yeah, maybe sending me the files you are using will help me figure out what's going on with IE9. |
Thank you for the response. I'm using the most recent version I saw, 2.3.2, and it does incorporate the document fragment. I'm not sure if there's any way of sending files to you through here, but I have uploaded to my SkyDrive, a 7Z archive with my table in a reduced html page from my Wordpress blog, and the supporting CSS/JS I currently load. You may download it at https://skydrive.live.com/redir.aspx?cid=2d523830bfdcb28e&resid=2D523830BFDCB28E!138&parid=2D523830BFDCB28E!132&authkey=!AH5dGubxkaFBKpw. Let me know if this works for you, or if there's a better way for me to send my files. Thank you. Update: I re-uploaded my archive just now because I realized I had left a file with an incorrect name. Silly me... |
I took a quick look at the file you shared last night and it was really slow, even in Chrome. I think it might be due to all of the custom fonts, most of which weren't found so that might have been part of the issue, on top of all of the data that needed to be processed. When I have more time today, I'll see how it does with basic styling and then test it in IE9. Have you considered setting up the table to work with ajax? |
Sorry about that. I guess I should've either included the fonts, or removed the references to them in the CSS. Interestingly, however, I just retested my test page (which does not have the fonts available), and it ran speedily for me, ~100ms to build the initial cache, and ~70ms to rebuild the table after sorts. Could it be a difference in our machines? I'm running on Windows 7 64-bit, with a Core i7-2630QM at 2 GHz... I haven't even finished my table's appearance in Webkit, if you may have noticed--the last column may appear disproportionately wide, ha. Anyway...as for ajax. No, I haven't gotten that far yet. It'd be something new for me to learn and to have to setup, and I have reservations about it, which discourages me from doing so. My impression is that if you load, say only the first 25 rows via ajax (I generate my table having the song titles sorted A-Z, so it looks sorted even without using sorting or without JS enabled), but then sort any column, say the song titles to Z-A, then all the data would have to get loaded and processed, anyway, right? Table rebuilds are what destroy IE9's performance. Please correct me if I'm wrong...I'd be up for considering AJAX if it really may help. |
Oh yeah, as for basic styling in IE9...I did test my page with all CSS disabled in IE9. While it shaves off a fair amount of time, about ~1000ms per rebuild, it's still extremely slow at ~1500ms. So, I don't think that's the main issue, especially since all other current browsers do just fine with the CSS, even IE8. |
Hmm, so I think the problem is actually the natural sort that I recently added. It uses a few functions like $(function(){
$.tablesorter.addParser({
id:'peak',
is:function(s){return false;},
format:function(s){
var strall = s.split('-'),
stra = parseInt(strall[1], 10),
strb = strall[0];
return strb + (100 - stra);
},
type:'numeric'
});
// Add a class to the body to indicate IE is running.
$('<!--[if IE]><script>jQuery("body").addClass("is-ie");</script><![endif]-->').appendTo('body').remove();
var options = {
debug: true,
headers: {
0: {sorter:false},
1: {sorter:'text'},
4: {sorter:'peak'}
},
cssAsc: 'hu',
cssDesc: 'hd',
cssHeader: 'he'
};
if ($('body').hasClass('is-ie')) {
// add very basic text sorter if IE is running
options.textSorter = function(a, b, table, column){
// this is the original sort method from tablesorter 2.0.5b
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
}
$('table')
.tablesorter(options)
.bind("sortStart",function(){
$("#overlay").show();
})
.bind("sortEnd",function(){
$("tbody th").each(function(i){
$(this).html(i + 1);
});
$("#overlay").hide();
})
.tablesorterPager({
container: $(".pager")
});
}); |
I tried implementing your suggestion...with it, I only saw savings of about 200ms per rebuild, and still quite a noticeable lag on each rebuild. But, with your suggestion in mind, I then additionally tried substituting in the digit and shortdate parsers from 2.0.5b. That didn't help much either, and in fact, I began getting wild variations in the rebuild times--they'd occasionally be under 2000ms, while at times, they'd jump to over 6000ms...crazy. Soon after, I thought of starting from scratch with 2.0.5b...surprisingly, that's fixed my issues with IE. Both IE8 and IE9 complete sorts and rebuilds in under 100ms, often even under 50ms. Wow. Incidentally, when I was first implementing tablesorter, I began with that version, but then upgraded to your update soon after I discovered it, because I figured newer would be better. I guess not always, though, if IE is just gonna choke on things. Anyway, I've run into another issue after downgrading to 2.0.5b. If I use the old pager plugin, I can't properly preserve my row numbers. For example, with a page size of 25 rows, I want page 2 to always be numbered 26-50, no matter what sort is active. This is possible with your plugin, because of the |
Hmmm, maybe it would be better to figure out why there is such a difference between the current version and 2.0.5b. I'd have to dig through the change log to remember what I added to the plugin core to make the |
I tested the earliest version I found on here, 2.0.6, and even then, IE9 was still as slow with the rebuilds as 2.3.2 is. I even attempted a comparison of 2.0.5 and 2.0.6 in Notepad++, using a feature to highlight differences between the files, but determined it would take me far too long to go through that, as nearly every line had something highlighted (perhaps mostly due to space formatting). I also discovered that you added I'm really frustrated with this. I think I just need to set this aside for a while, or maybe just look at it with fresh eyes tomorrow (or later in the week)--I've got far more other work to do in preparing my site, anyway, and hate that this issue has hung me up for a few days already. Please let me know if you think of any other ways to try to fix IE9's performance. Thank you. |
I've finally achieved a breakthrough!!!!!111!!!1 Haha. So, I ultimately realized that IE will apparently never see decent performance if (function(d){d.extend({tablesorterPager:new function(){var l=function(a){a.updateArrows&&(a.container.removeClass(a.cssDisabled),d(a.cssFirst+","+a.cssPrev+","+a.cssNext+","+a.cssLast,a.container).removeClass(a.cssDisabled),a.page===0?d(a.cssFirst+","+a.cssPrev,a.container).addClass(a.cssDisabled):a.page===a.totalPages-1&&d(a.cssNext+","+a.cssLast,a.container).addClass(a.cssDisabled),a.totalRows<a.size&&a.container.addClass(a.cssDisabled))},o=function(a,b){b.startRow=b.size*b.page+1;b.endRow=Math.min(b.totalRows, b.size*(b.page+1));var c=d(b.cssPageDisplay,b.container),e=b.output.replace(/\{(page|totalPages|startRow|endRow|totalRows)\}/gi,function(a){return{"{page}":b.page+1,"{totalPages}":b.totalPages,"{startRow}":b.startRow,"{endRow}":b.endRow,"{totalRows}":b.totalRows}[a]});c[0].tagName==="INPUT"?c.val(e):c.html(e);l(b);b.container.show();d(a).trigger("pagerComplete",b)},m=function(a){var b=a.config,a=d(a);if(!b.pagerPositionSet&&b.positionFixed)a.offset&&b.container.css({top:a.offset().top+a.height()+ "px",position:"absolute"}),b.pagerPositionSet=!0},k=function(a,b){var c,e=d("tr",a.tBodies[0]),h=e.length,j=b.page*b.size,f=j+b.size;f>h&&(f=h);for(c=0;c<h;c++)e[c].style.display=c>=j&&c<f?"":"none"},i=function(a,b){var c,e,h,j,f=a.config,g=b.length;c=f.page*f.size;var i=c+f.size;d(a).trigger("pagerChange",f);if(f.removeRows){if(i>b.length)i=b.length;j=d(a.tBodies[0]);for(d.tablesorter.clearTableBody(a);c<i;c++){h=b[c];g=h.length;for(e=0;e<g;e++)j[0].appendChild(h[e])}}else k(a,f);m(a,j);d(a).trigger("applyWidgets"); f.page>=f.totalPages&&n(a);o(a,f)},
g=function(a){var b=a.config;if(b.page<0||b.page>b.totalPages-1)b.page=0;i(a,b.rowsCopy)
/*
Fix absymal slowness in IE9+, and speed up the slightly sluggish IE8 and Opera.
Basically fakes effect of "removeRows:false" even when it's actually set to true,
by calculating correct row numbers based on current page.
*/
if ($.browser.msie || $.browser.opera)
{var $ths = $("tbody th"); $ths.each(function(i){$(this).html((i+1)+(parseInt($(".pagesize").val())*(parseInt($(".pd>i").html())-1)));})}
},
n=function(a){var b=a.config;b.page=b.totalPages-1;g(a)};this.appender=function(a,b){var c=a.config;c.rowsCopy=b;c.totalRows=b.length;c.totalPages=Math.ceil(c.totalRows/c.size);i(a,b)};this.defaults={size:parseInt($(".pagesize").val(),10),offset:0,page:0,totalRows:0,totalPages:0,container:null,cssNext:".next",cssPrev:".prev",cssFirst:".first",cssLast:".lastp",cssPageDisplay:".pd",cssPageSize:".pagesize", cssDisabled:"di",output:"Page <i>{page}</i> of {totalPages}",updateArrows:!1,positionFixed:false,
removeRows:true,
appender:this.appender};this.construct=function(a){return this.each(function(){var b=d.extend(this.config,d.tablesorterPager.defaults,a),c=this,e=b.container;d(this).trigger("appendCache");b.size=parseInt(d(".pagesize",e).val(),10);l(b);if(!b.removeRows)b.appender=null,k(c,b),d(this).bind("sortEnd.pager",function(){k(c,b);d(c).trigger("applyWidgets")});d(b.cssFirst,e).click(function(){c.config.page= 0;g(c);return!1});d(b.cssNext,e).click(function(){var a=c.config;a.page++;if(a.page>=a.totalPages-1)a.page=a.totalPages-1;g(c);return!1});d(b.cssPrev,e).click(function(){var a=c.config;a.page--;if(a.page<=0)a.page=0;g(c);return!1});d(b.cssLast,e).click(function(){n(c);return!1});d(b.cssPageSize,e).change(function(){var a=parseInt(d(this).val(),10),b=c.config;b.size=a;b.totalPages=Math.ceil(b.totalRows/b.size);b.pagerPositionSet=!1;g(c);m(c);return!1});d(this).bind("destroy.pager",function(){var a= c.config;a.size=a.totalRows;a.totalPages=1;i(c,a.rowsCopy);a.container.hide();a.appender=null;d(c).unbind("destroy.pager sortStart.pager")})})}}});d.fn.extend({tablesorterPager:d.tablesorterPager.construct})})(jQuery);
var options = {debug:true,headers:{0:{sorter:false},1:{sorter:'text'},4:{sorter:'peak'}},cssAsc:'hu',cssDesc:'hd',cssHeader:'he'};
$('form.pager').show();
if ($.browser.msie || $.browser.opera)
{$('table').tablesorter(options)
.bind("sortEnd",function(){$ths = $("tbody th");$ths.each(function(i){$(this).html((i+1)+(parseInt($(".pagesize").val())*(parseInt($(".pd>i").html())-1)));});})
.tablesorterPager({container: $("form.pager")})}
/* For all other browsers, use my regular config */
else { $('table').tablesorter(options)
.bind("sortEnd",function(){$ths = $("tbody th");$ths.each(function(i){$(this).html(i+1);});})
.tablesorterPager({removeRows:false, container: $("form.pager")}) }; Pretty cool, huh? I'm actually using version 2.0.21 of the tablesorter (unmodified min) and the pager currently. I tried my changes on 2.3.2 of both, and for some reason, I got rebuild times of 900-1000ms in IE9. While barely within an acceptable range for me, it's still a LONG way off from my best times of 9-10ms I'm getting with 2.0.21. Not even my usual speed champ, Firefox, can beat that! (It gets ~20ms--definitely still blazing) I'll test Versions 2.1 and 2.2, to see if I can find when IE9 starts slowing down. But aside from that, things are going much better now! |
That's great to hear! |
So, I think I'm gonna stick with the most recent 2.0.X version of Tablesorter I've found, 2.0.31, along with its corresponding pager (dated 2/16/12). Something changed between 2.0.X and 2.1.X, to cause IE9's rebuild times to slow to 700-1000ms, and I'm not quite sure what. I don't think it's worth my time anymore to try to figure it out, since I have now have everything working well enough: fast speeds in every current browser, and paging with correct row numbers. I even made my changes default to all browsers (instead of just IE and Opera), and that speeds things up for everyone. Firefox is my speed champ once again again with ~5ms rebuilds, haha, but Chrome ties it, and even occasionally edges ahead at ~2-3ms...simply phenomenal. Now, Opera is the one bringing up the rear, with ~250ms sorts and ~15ms rebuilds--still nothing to complain about, though. Although I usually prefer using the latest version of scripts, I see no compelling reason for me to upgrade to 2.3.X, since it slows down IE somewhat. If this is something worth your looking to, then go for it. Otherwise, I am fine where I'm at, and you may close this issue. Thanks for your help, Mottie! |
Ok, no worries. I do appreciate all of the troubleshooting that you've done! I'll find a better solution :) |
You're welcome! I'll keep an eye out for any new updates, and, if I can help with any more troubleshooting, I'd be glad to. |
Ok, I think I've improved sorting, rendering and even widget performance in IE9. I actually ended up removing the document fragments in some cases (in the widgets) as IE9 performed better without them and just hiding the tbody turned out to be better. I didn't change the appendToTable function much except to hide the tbody while appending, it seems to work better. In my optimizations, I also found that parsing the data was extremely slow in IE9, so I opted for the fastest method of using Now, I think one of the biggest issues in IE9 was the zebra widget. I noticed insanely slow times so I revert it back to the original code and oddly it was faster; but as a result, I added a new option named I don't remember you using the filter widget, but just in case... I've also added a few filter widget options to delay searching which was also needed because of IE9 being so darn slow LOL. |
I've finally gotten around to testing 2.3.5 and the updated pager, and running comparisons with my previous setup of 2.3.4 and the pager dated 2/16/12. IE9 did show some speed improvements in 2.3.5, such as 75-80ms initial cache build time for 738 rows, and overall init times of ~220ms. That included about 100ms time to apply my widget. I wouldn't have known of the widget time without the benchmark you put for timing them in 2.3.5, so, thanks for that! My only widget is repeated headers, visible every 25 rows. However, since by default, I have my table set to show exactly 25 rows per page, that means the repeated headers aren't visible unless the page size is increased. So, I wrapped my widget into an (if pagesize > 25) statement, and then wrappped that in a function bound to the pagesize selector. Now, my widget only loads when needed, and that shaves ~100ms off my init time, that I didn't even know was there, haha. So, minus my widget now, init times averaged about 120ms in IE9 under 2.3.5. Pretty good. Initial cache build time was about 50ms higher under 2.3.4, meaning a nice ~30% improvement for me. However, rebuild times are still sluggish with the latest pager. The initial rebuild clocks in at over 1200ms, compared at ~350ms with 2.3.4 and the 2/16/12 pager. The times are about the same with 2.3.5 and the 2/16/12 pager, as well. Sorts/rebuilds are also fairly sluggish with the new pager, averaging about 950ms...a far cry from the 20-25ms I'd get with the older pager. I don't get it...I've tried comparing the differences between the 2/16/12 and 3/7/12 (I think that was the date? It was an early March that first exhibits the slower speeds in IE) pager, as well as the latest pager, and I can't pinpoint the slowdown. So, for now, I am sticking with the 2/16/12 pager. Now, IE9 may not have seen great results with both the new sorter and pager, but IE8 actually saw more of an improvement. Weird, haha. Under 2.3.4 and the old pager, IE8 would get ~1400ms initial cache build times, and ~150ms initial rebuild times. Sorts/rebuilds would average 30ms or less. Now, with 2.3.5 and the new pager, initial cache build times were cut in half, to around 700ms--very good! But, the initial rebuild time slowed to ~500ms, and sorts/rebuilds would take ~550ms. Putting back the older pager brings those times back down, however, to ~250ms and 20-30ms, respectively. So, with both IEs, 2.3.5 and the older pager gives me the best performance...that's what I'll be sticking with for now. However, 2.3.5 initially messed up my custom parser, only in IE8...yay, you just gotta love IE8 and its quirks, right? Haha, not! I traced the issue to I determined that IE8 doesn't support the vastly superior I've definitely had enough of IE8 for one day, or one week...actually, if I didn't have to put up with its quirks ever again, I'd be great! Haha. |
@Mottie why not just remove the table from the DOM , do your logic then append it back? |
@thezoggy Well since I never know how the table is placed in the document, it's better not to remove it. For example, if I use the recommendation from that site and a table's parent is the body of the document. It gets removed, manipulated then appended back to the body... well now the table is at the bottom of the page. I guess I could wrap it and do all that stuff. Anyway, I just switched to using document fragments because you can move all of the tbody contents into it, then append them back without removing the tbody itself... but as you can see, it's even slower in IE. The I guess I'll try wrapping the table, removing, manipulating then appending it back just to see if IE is any happier. But let me finish working on this filter regex thing. |
additionally, here is another way people can speed up tables.. however there is a trade off:
Using the “automatic” layout algorithm (the table algorithm used by default in most browsers today), all of the table content is required in order to determine the final table layout. For larger quantities of tabular data, this can be MUCH slower than the “fixed” table layout algorithm, especially since more than one analysis might need to be performed on the table data. However, this algorithm does find sufficient minimum and maximum widths for each column, allowing all content in the table’s data cells to be appropriately rendered as specified by the author. Under the “fixed” layout method, the entire table can be rendered once the first table row has been downloaded and analyzed. This can drastically speed up rendering time over the “automatic” layout method, but subsequent cell content may not fit in the column widths provided (the ‘clip’ and ‘overflow’ properties control the cell appearance in such a case.) Thus if your table's column data length doesn't really vary from the 1st row onward.. then you could use this and save the browser a bit of work. Now if it does vary.. you'd have to deal with overflows/scrollbars/ugly things.. and no way would this be responsive (resize). Thus this feature is rarely used.. but still I figured I'd mention it since I came across it recently in my hunt for table optimizations. |
Another update in v2.4. The tbody's are now detached then manipulated. There is a noticeable speed increase when sorting large tables. |
Hello, Mottie. I've been testing your fork of tablesorter on a personal site I'm developing locally, and have been pleased with the results--well, mostly.
On a table of 11 columns and 700+ rows (consisting of stats on songs I have charted on a weekly top 50), with the pager plugin enabled, I get results like these:
Firefox 12: Builds initial cache in ~200ms, sorts digit columns in <10ms, shortdate columns in <20ms, one pure text column in ~40ms, and one text column with embedded markup (hereafter referred to as "markup") in ~200ms. The table gets rebuilt after each sort in ~20ms (Overall blazing fast!)
Firefox 3.6: Builds initial cache in ~300ms, sorts digit columns in ~25ms, shortdate columns in ~50ms, the pure text column in ~100ms, and the markup column in ~2000ms (oddly slower). Table rebuilds each time in ~90ms. (With the exception of the markup column, still very fast, but am not worried about it, since I'm not planning on supporting FF 3.5/3.6 for long.)
Now, to speed things along a bit, I'll just summarize the results of some other browsers:
Chrome 18 and Safari 5.1: Speeds slightly slower than Firefox, but we're only talking differences of less than 100ms, and often less than ~50ms. Performance feels just as snappy.
Opera 11.6: I did notice unusually slower initial cache build times (~6000ms), slower sorts (~100-250ms depending on column type), and slower rebuilds (~500-1000ms). Opera definitely feels slower, but still performs acceptably, in my opinion.
But now, here comes the wall I've run in to:
IE9: It builds the initial cache in ~200ms. That is perfectly okay. It even sorts columns quite fast (<10ms for the date and digit columns and ~50ms for the text column), except for the markup column, which comes in at a much slower ~900ms. However, rebuilds absolutely destroy performance: 2500ms on average for each sort! During which, the table appears frozen... I figured I could at least give visual feedback by showing an overlay with "Please Wait" during the sort phase, as you demoed, but for some reason, IE does not show it (it will show in every other browser, though.) In profiling the script, I've ruled that the
appendToTable
function is the bottleneck, specifically theappendChild
in the loop iterating over all the rows. I guess IE is just horribly slow at DOM manipulation...? Things were no better when I tested in the latest available preview of IE10 for Windows 7 (more recent previews are only available on Win 8 previews currently, which I have no desire to install so far.)However! IE's JS performance really insults me, in that IE8 is faster! Huh? Check out my numbers:
IE8: It builds the initial cache in ~900ms. Okay, so that's actually slower. And, sort speeds compare to IE9, except for the text/markup columns, which are about 2/3 to 3/4 the speed of IE9's sorts. However, table rebuilds are significantly faster: 200-400ms on average for each sort--IE8 is up to 10 times faster than IE9!
IE7: I tested this just for kicks, even though I'm not supporting IE7 or lower on my site. It builds the initial cache in ~1600ms, sorts columns at comparable speeds to IE8, but rebuilds the table significantly slower than IE8, at ~800-900ms. That's still up to 3 times faster than IE9!
I've tried so much to debug IE9's abysmal performance. Knowing that I have IE9 apply more CSS to my tables than IE8, such as box-shadow, border-radius, and SVG background gradients, I experimented with disabling all CSS. This resulted in average savings of 1000ms for each table rebuild, but that is not enough, as that leaves the times at a still way-too-slow ~1500ms. I also ran the same experiment in IE8, and saw its rebuild times decrease a bit to ~180-250ms. While the savings, especially in IE9, do help, there's no way I'd leave my tables unstyled...especially when all the other better browsers perform admirably with the CSS included.
I've also tried streamlining the
appendToTable
function on my own...but, I'm no JS expert. Knowing that my table will always have only one tbody, I moved script out of the loop that iterates over the tbodies, and then removed the loop. And, knowing I have no need for cssinfoblock, I removed the check for that...so far, none of that has been enough, though. In the loopfor (i = 0; i < totalRows; i++)
,f.appendChild(r[pos][j]);
is the bottleneck I've zeroed in on. I've been trying to figure out some way to do that appending outside the loop, to reduce the calls toappendChild
from 700+ down to 1, theoretically leading to the speed improvement I seek. However, I'm at the end of my current JS knowledge. Anything I've tried keeps resulting in DOM exceptions... Is it possible to append an array of objects to the DOM? I know currently,table.tBodies[k].appendChild(f);
appends the created document fragment of rows, to the tbody. In its place, I've been trying to come up with a way to do something liketable.tBodies[0].appendChild(r[*entire pos array*][*tablerow element in each part of pos array*]);
and removef.appendChild(r[pos][j]);
, but I'm not getting anywhere. Maybe I have the wrong approach? Like I said, I'm not an expert in JS... Do you have any suggestions on how to solve IE9's slowness?If you want, I can gather together my table and relevant CSS, if it helps. However, in your triggers sortEnd and sortStart demo page, you can witness slowdowns proportional to mine with my table. On my machine, FF, Chrome, Safari, and Opera all tend to sort the columns in .1 seconds or less (sometimes taking a little longer on the first two text columns), while IE9 is never faster than .1 second, and will take .8-1.2 seconds on those text columns. IE8 stays under 1 second on those two columns, but still comes up slow at over .8 seconds. Finally, as a real head-scratcher, IE7 stays under .5 seconds on those two columns, and even comes in at under .2 seconds for the second column (comparable to the rest of the columns). I just don't get this, haha.
Please let me know if there's any way you can help me. And again, if I can help too, like by giving you my testing code, I'd be glad to...thanks in advance!
The text was updated successfully, but these errors were encountered: