I'm trying to understand why it takes so long to rebuild a table using javascript on Firefox 43.0.2
A simplified version of my code is below. Both the "real" code and the simple version use "publishTable() to add rows to a table. PublishTable deletes a table body element if it exists, creates a new one, adds about 9000 rows to it, and attaches the completed table body to the table.
PublishTable runs on load, and when the user clicks a "go" button. Therefore, I expect performance to be similar on load and rebuild.
When the "real" page first loads, Firefox takes about 300ms to construct the table [according to performance.now()]. When the alert() announcing this result is closed, i can immediately scroll the page up and down.
But if i click the "go" button to rebuild the table, Firefox spins its wheels for tens of seconds (or more) after I close the alert() dialog. A "stop script?" dialog can appear more than once. The simple version behaves similarly.
So:
Why is the performance so radically different between initial build, and rebuild? It seems clearly possible to build the table in 300ms! Is there anything I can do about it?
Some further observations:
IE's performance is much worse on initial load, and as bad on rebuild. Chrome's performance is pretty good: 2 seconds to build or rebuild.
If I use innerHTML, rather than insertRow, appendChild, etc., results are similar.
If i remove the line attaching the table body to the table, the wheel-spinning symptom does not occur.
In the "waterfall" chart (in the Firefox performance tool), the the "DOM event" takes up much more time than the "event handler" (which I think covers the run-time of my code), and I don't know what that means. What is happening between the time the js stops running, and the DOM event ends, that doesn't fall in one of the other waterfall categories?
The DOM event is followed by a brief time to recalculate style, a time to paint, and then a sequence of many "cycle collection" periods, then "incremental gc", "cc graph reduction", "cycle collection", "graph reduction", and so on, for tens of seconds. In one case, the performance call-tree allocated 49 seconds to "Gecko" (which seems to be idle time) and another 25 seconds to "graphics" (and within that, a mere 1 second is allocated to publishTable()). Is there something here I can act on?
I'm out of reasonable ideas for further analysis, or how I might modify the js. I don't understand enough about the performance information to act on it. (And now, after timing with IE and Chrome, I'm not even sure to whom the question should be addressed.)
Is there a fundamental error in the code? A better table construction strategy? A way to use the performance tool to understand the problem? A bug in Firefox? (And now I'm going to do the thing on the server side. But I'm still curious about what's going on.)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id='a'>
<button type="button" disabled id="btnGo">Go</button><br />
<button type="button" id="btnQ">?</button><br />
<table id="tideTable" style="Width:40%;margin-left:auto;margin-right:auto;">
</table>
</div>
<div id="b">
hello
</div>
<script>
(function() {
var mmm = ['one', 'two', 'three', "four", "five", "six", "seven"];
function publishTable() {
// The user may run this several times, varying some parameters each time.
var tStart = performance.now();
var table = document.getElementById('tideTable');
// var tableBody = table.getElementsByTagName('tbody')[0];
var tableBody = table.tBodies[0];
if (tableBody) {
tableBody.parentNode.removeChild(tableBody);
}
showHeight();
tableBody = document.createElement('tbody');
for (var i=0; i < 8500; i++) {
appendTableRow(tableBody, mmm);
}
table.appendChild(tableBody);
document.getElementById("btnGo").disabled = false;
alert("Time: " + (performance.now() - tStart) + "ms");
showHeight();
}
function appendTableRow(tableBody, columns) {
var cell;
var textNode;
var row = tableBody.insertRow(-1);
for (var i = 0; i < columns.length; i++) {
cell = row.insertCell(i);
textNode = document.createTextNode(columns[i]);
cell.appendChild(textNode);
}
}
function showHeight(){
var el = document.getElementById('b');
var topPos = el.offsetTop;
alert("position: " + topPos);
}
document.getElementById("btnGo").addEventListener("click", publishTable);
document.getElementById("btnQ").addEventListener("click", showHeight);
publishTable();
})();
</script>
</body>
</html>
` and watch your table move ;)
– zer00ne Dec 28 '15 at 22:29