我需要显示由某些数字配置创建的视觉模式,以及它们之间的关系。为此,我创建了一个表并使用行/列作为 x/y 坐标(以 ID 编码)。对于许多 TD 元素,我提供了有意义的背景颜色并附加了 mouseover/out 处理程序以显示一个带有该 TD 分配的编号和有关它的信息的弹出窗口。(单元格太小而无法实际包含数字;它们更像是一种视觉设备,我使用上述背景颜色,因此可以很容易地看到图案。)
我需要能够放大和缩小此表,以及以其他方式对其进行管理。但是,在处理大型表(1000 行和列,或更多)时,浏览器需要花费大量时间在每个新的缩放级别呈现它。做了一些研究,我发现 TABLE 元素需要更多的汁液,因为浏览器必须根据表格中的单元格内容和可用宽度重新计算。将'table-layout'设置为'fixed'并给表格一个宽度应该可以防止这种情况发生,但它仍然需要很长时间。
然后我认为用 DIV 元素制作一个表格可能会起作用,因为这将需要更少的总元素并且没有像表格那样的自动调整大小 - 我可以对尺寸进行硬编码。我尝试了一些我在网上找到的代码,使用“display: table”(以前从未听说过),以及非表格化的 DIV(喜欢编造词......)。
这是我创建的一个测试页面,用于测试这三个并为它们计时(在此处查看):
<!--
Only tested in Google Chrome on Windows 7!
I have not bothered testing in other browsers as this is a private project
and all members of the project use Chrome.
-->
<html>
<head>
<title>Table Test</title>
<style>
#controls td {
font-family: Courier New, monospace;
}
input[type=button] {
width: 100%;
}
input[type=text] {
width: 50px;
}
/* styles the pure table version */
table {
table-layout: fixed;
border-collapse: collapse;
}
.td {
border: 1px solid black;
width: 48px;
height: 48px;
vertical-align: top;
}
/* styles the DIV version using "display: table" */
.div-table {
display: table;
border: solid black;
border-width: 1px 0px 0px 1px;
}
.div-table-row {
display: table-row;
width: auto;
clear: both;
}
.div-table-col {
float: left;
display: table-column;
width: 48px;
height: 48px;
border: solid black;
border-width: 0px 1px 1px 0px;
}
/* styles the pure DIV version */
div#grid {
border: solid black;
border-width: 1px 0px 0px 1px;
}
.cell {
display: inline-block;
width: 49px;
height: 49px;
padding: 0px;
margin: 0px;
border: solid black;
border-width: 0px 1px 1px 0px;
}
</style>
<script type="text/javascript">
function Stopwatch() { // basic Stopwatch object to time functions
var startTime = null;
var stopTime = null;
var running = false;
function getTime() {
var day = new Date();
return day.getTime();
}
this.start = function() {
if (running == true)
return;
else if (startTime != null)
stopTime = null;
running = true;
startTime = getTime();
return startTime;
}
this.stop = function() {
if (running == false)
return;
stopTime = getTime();
running = false;
return stopTime;
}
this.duration = function() {
if (startTime == null || stopTime == null)
return 'Undefined';
else
return (stopTime - startTime) / 1000;
}
}
var stopwatch = new Stopwatch();
var x = 50; // global dimension variables
var y = 100;
function updateDims() { // updates the global dimension variables
// returns true/false to indicate success
x = parseInt(document.getElementById('x').value);
y = parseInt(document.getElementById('y').value);
if (typeof x == 'number' && x > 0 && typeof y == 'number' && y > 0) return true;
return false;
}
function makeTableTable() { // creates the pure table version
if (!updateDims()) return false; // grab desired x/y dimensions
// grab count of how many times function has been run to calculate average
var count = document.getElementById('count1');
count = count.value = parseInt(count.value) + 1;
// grab previous average time to calculate new average
var avg = parseFloat(document.getElementById('avg1').innerHTML);
// start the stopwatch, grabbing initial start time, and begin concatenating
var start = stopwatch.start();
var html = '<table id="grid" cellpadding="0" cellspacing="0">';
for (var i = 0; i < y; i++) { // for each row...
html += '<tr>';
for (var j = 0; j < x; j++) { // build desired number of cells
html += '<td class="td" id="'+j+'/'+[y-[i+1]]+'">' + [1+j+i*x] + '</td>';
}
html += '</tr>'; // close row
j = 0;
}
html += '</table>';
// stop the watch and record duration it took to concatenate
stopwatch.stop();
document.getElementById('concat1').innerHTML = stopwatch.duration();
// start the watch again and insert HTML
stopwatch.start();
document.getElementById('output').innerHTML = html;
// stop the watch, grabbing the final end time, and record duration for innerHTML
var end = stopwatch.stop();
document.getElementById('insert1').innerHTML = stopwatch.duration();
// find total time from initial start time and final end time
document.getElementById('total1').innerHTML = (end - start) / 1000;
// calculate average time
if (count > 1)
document.getElementById('avg1').innerHTML = Math.round(100000*(avg*(count-1)+(end-start)/1000)/count)/100000;
else
document.getElementById('avg1').innerHTML = (end-start) / 1000;
}
function makeDivTable() { // creates the DIV version using "display: table"
if (!updateDims()) return false;
var count = document.getElementById('count2');
count = count.value = parseInt(count.value) + 1;
var avg = parseFloat(document.getElementById('avg2').innerHTML);
var start = stopwatch.start();
var html = '<div id="grid" class="div-table">';
for (var i = 0; i < y; i++) {
html += '<div class="div-table-row">';
for (var j = 0; j < x; j++) {
html += '<div class="div-table-col" id="'+j+'/'+[y-[i+1]]+'">' + [1+j+i*x] + '</div>';
}
html += '</div>';
j = 0;
}
html += '</div>';
stopwatch.stop();
document.getElementById('concat2').innerHTML = stopwatch.duration();
stopwatch.start();
document.getElementById('output').innerHTML = html;
var end = stopwatch.stop();
document.getElementById('insert2').innerHTML = stopwatch.duration();
document.getElementById('total2').innerHTML = (end - start) / 1000;
if (count > 1)
document.getElementById('avg2').innerHTML = Math.round(100000*(avg*(count-1)+(end-start)/1000)/count)/100000;
else
document.getElementById('avg2').innerHTML = (end-start) / 1000;
// update width of outer DIV
document.getElementById('grid').style.width = 50 * x + 'px';
}
function makeDivDiv() { // creates the pure DIV version
if (!updateDims()) return false;
var cells = x*y; // will iterate through total number of cells,
// rather than by row and column
var count = document.getElementById('count3');
count = count.value = parseInt(count.value) + 1;
var avg = parseFloat(document.getElementById('avg3').innerHTML);
var start = stopwatch.start();
var html = '<div id="grid">';
for (var i = 0; i < cells; i++) {
var id = [i-x*Math.floor(i/x)+1] + '/' + [y-Math.floor(i/x)];
html += '<div class="cell" id="' + id + '">' + [i+1] + '</div>';
}
html += '</div>';
stopwatch.stop();
document.getElementById('concat3').innerHTML = stopwatch.duration();
stopwatch.start();
document.getElementById('output').innerHTML = html;
var end = stopwatch.stop();
document.getElementById('insert3').innerHTML = stopwatch.duration();
document.getElementById('total3').innerHTML = (end - start) / 1000;
if (count > 1)
document.getElementById('avg3').innerHTML = Math.round(100000*(avg*(count-1)+(end-start)/1000)/count)/100000;
else
document.getElementById('avg3').innerHTML = (end-start) / 1000;
document.getElementById('grid').style.width = 50 * x + 'px';
}
</script>
</head>
<body>
<table id="controls" border="1">
<tr>
<td>x: <input type="text" id="x" value="50" /></td>
<td>y: <input type="text" id="y" value="100" /></td>
<td colspan="7"></td>
</tr>
<tr>
<td><input type="button" onclick="makeTableTable()" value="Standard table" />
<input type="hidden" id="count1" value="0" /></td>
<td>Concatenation:</td>
<td id="concat1"> </td>
<td>Insertion:</td>
<td id="insert1"> </td>
<td>Total:</td>
<td id="total1"> </td>
<td>Average:</td>
<td id="avg1"> </td>
</tr>
<tr>
<td><input type="button" onclick="makeDivTable()" value="Div w/ 'display:table'" />
<input type="hidden" id="count2" value="0" /></td>
<td>Concatenation:</td>
<td id="concat2"> </td>
<td>Insertion:</td>
<td id="insert2"> </td>
<td>Total:</td>
<td id="total2"> </td>
<td>Average:</td>
<td id="avg2"> </td>
</tr>
<tr>
<td><input type="button" onclick="makeDivDiv()" value="Div Table" />
<input type="hidden" id="count3" value="0" /></td>
<td>Concatenation:</td>
<td id="concat3"> </td>
<td>Insertion:</td>
<td id="insert3"> </td>
<td>Total:</td>
<td id="total3"> </td>
<td>Average:</td>
<td id="avg3"> </td>
</tr>
</table><br />
<div id="output"></div>
</body>
</html>
首先尝试使用较小的值,例如默认值。然后尝试将 x 和 y 更改为 1000,并尝试默认浏览器缩放功能。生成表格以及放大或缩小都需要相当长的时间。
不过,有趣的是,据报道所用的时间显然不是它实际所用的时间——人们可以通过计算棒球场的秒数来看出这一点(很好的“一个密西西比州”)。当报告的几次运行后的平均时间约为 2.3、2.7 和 2.4 时,400x400 的网格分别持续大约 13 秒、5 秒和 7 秒。所有与时间相关的代码都不会对其产生太大影响。您可以将其全部删除或将其全部注释掉(查看),它是相同的(对我来说是 13、5 和 7)。
所以两个问题:
首先,为什么这些数字有差异?计时器应该对函数中发生的所有事情进行计时。除了第一次调用 updateDims 之外,发生的主要两件事是字符串连接和对 innerHTML 的赋值。(网格的宽度也发生了变化,但我看不出这会花费多少时间。)它只是浏览器渲染时间,在函数完成后发生,所以没有计时?支持这一点的一些证据是纯表格版本的明显时间要长得多,这意味着浏览器可能正在重新计算所有 TD 宽度等。
其次,可以做些什么呢?任何事物?串联是其中的一小部分,所以这不是问题。(而且我已经尝试推入一个数组并加入,并且连接始终更快,至少对我来说是这样。)此外,如果要相信秒表,将它插入到 innerHTML 不会花费那么长时间。这就是后来发生的任何事情。我曾考虑过使用后台程序技术,因此即使需要一段时间来更新,至少它不会一直锁定浏览器并且会进行一些明显的活动。但是如果锁定点发生在函数的“外部”,我看不出它是如何工作的。我可以设计自己的缩放功能,但我不相信它会比浏览器更快。初步测试说没有。
我正在尝试做的任何其他选择(尽管它可能对你来说很模糊;对不起)当然值得赞赏!
StackOverflow 上的其他一些页面:
大型 html 表慢吗?听起来好像表格通常可以快速渲染。但是,这可能只适用于已经硬编码到 HTML 文件中的表格,而不是像我的那样生成的。
创建大表的 Javascript 性能与我的情况非常相似,除了具有分页表的公认解决方案对我来说不是一个选项,因为这会破坏目的。而且我的表不包含数据。然而,其中一位受访者确实暗示,对于如此大的表,DOM 方法可能比 HTML 解析更快(尽管我在其他地方看到相反的情况;可能有合理数量的元素)。当我有机会时,我可能会测试一下。你怎么看?