我试图理解为什么在Firefox 43.0.2上使用javascript重建表需要这么长时间
我的代码的简化版本如下。 “真实”代码和简单版本都使用“publishTable()来向表中添加行。如果表格元素存在,则删除表格主体元素,创建一个新元素,向其添加大约9000行,并附加已完成的表格主体到桌子。
PublishTable在加载时运行,当用户单击“go”按钮时。因此,我希望在加载和重建时性能类似。
首次加载“真实”页面时,Firefox需要大约300ms才能构建表格[根据performance.now()]。当宣布此结果的alert()关闭时,我可以立即上下滚动页面。
但是,如果我单击“go”按钮重建表格,Firefox关闭alert()对话框后会旋转数十秒钟(或更长时间)。一个“停止脚本?”对话框可以出现多次。简单版本的行为类似。
所以:
为什么在初始构建和重建之间的性能如此根本不同?显然可以在300ms内构建表格!我有什么可以做的吗?
进一步的观察:
IE的性能在初始加载时更差,在重建时也差。 Chrome的性能相当不错:构建或重建2秒。
如果我使用innerHTML,而不是insertRow,appendChild等,结果是相似的。
如果我移除了将桌子主体连接到桌子上的线条,则不会发生轮子旋转症状。
在“瀑布”图表中(在Firefox性能工具中),“DOM事件”占用的时间远远超过“事件处理程序”(我认为它涵盖了代码的运行时),而我不知道那意味着什么。在js停止运行和DOM事件结束之间发生了什么,这不属于其他瀑布类别之一?
DOM事件之后是短暂的时间重新计算样式,绘制时间,然后是许多“循环收集”期间的序列,然后是“增量gc”,“cc图缩减”,“循环收集”, “图形缩减”等等,持续数十秒。在一种情况下,性能调用树为“Gecko”(似乎是空闲时间)分配49秒,为“图形”分配另外25秒(并且在其中,仅仅1秒分配给publishTable())。我可以采取行动吗?
我没有合理的想法进行进一步分析,或者我如何修改js。我对表现信息的理解不够了解。 (现在,在使用IE和Chrome计时之后,我甚至不确定应该向谁解决这个问题。)
代码中是否存在根本错误?更好的餐桌建设策略?一种使用性能工具来理解问题的方法? Firefox中的一个错误? (而现在我将在服务器端做这件事。但我仍然对正在发生的事情感到好奇。)
<!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>
答案 0 :(得分:1)
我想,可能是因为在插入新项目之前删除了现有项目。您可以尝试以下方法:
如果您只是扩展表格而没有删除,请确保性能会发生什么
在插入表格之前构建表格,例如创建一个变量tableContent将行放入其中,然后将tableContent添加到表中,这应该更快,因为浏览器必须在每个插入时重新呈现页面。
我建议你考虑使用angularJS,如果你打算让表动态
答案 1 :(得分:1)
您的JS已缩小并位于CloudFront CDN中。
The first demo is async
and the second demo is defer
异步
https://jsfiddle.net/zer00ne/6m9f24j5/
推迟
https://jsfiddle.net/zer00ne/fcpy9z0c/
结果
同样。
火箭加载时142毫秒。
每次点击活动平均230毫秒。
Chrome加载时846毫秒。
每次点击活动的平均值为930毫秒。
将<script>
代码置于结束</body>
代码
https://jsfiddle.net/zer00ne/y7mguyry/
(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];
if (tableBody) {
tableBody.parentNode.removeChild(tableBody);
}
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");
}
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);
}
}
document.getElementById("btnGo").addEventListener("click", publishTable);
publishTable();
})();
<button type="button" disabled id="btnGo">
Go</button>
<br />
<table id="tideTable" style="Width:40%;margin-left:auto;margin-right:auto;">
</table>
答案 2 :(得分:1)
我尝试换掉这条线:
var tableBody = table.getElementsByTagName('tbody')[0];
内置的getter:
var tableBody = table.tBodies[0];
这似乎可以稳定构建时间。仍然有点慢,但初始构建和重建报告几乎一致的时间。
这可能是巧合,但你可能想要搞清楚。