我需要显示由某些数字配置创建的视觉模式,以及它们之间的关系。为此,我创建了一个表,并使用行/列作为x / y坐标(以ID编码)。对于许多TD元素,我给出了一个有意义的背景颜色并附加了鼠标悬停/输出处理程序,以显示一个弹出窗口,其中包含该TD指定的编号和相关信息。 (单元太小,实际上不包含数字;它们更像是一个可视设备,我使用所说的背景颜色,因此可以很容易地看到图案。)
我需要能够放大和缩小此表,以及以其他方式管理它。但是,在处理大型表(1000行和多列或更多)时,浏览器需要花费大量时间在每个新的缩放级别进行渲染。做了一点研究,我看到TABLE元素需要多一点,因为浏览器必须根据表格中的单元格内容和可用宽度重新计算。将'table-layout'设置为'fixed'并为表提供宽度应该可以防止这种情况发生,但它仍然需要永远。
然后我认为用DIV元素制作一个表可能会起作用,因为这需要更少的总元素,并且没有像表那样的自动调整大小 - 我可以硬编码尺寸。我尝试了一些我在网上找到的代码,使用“display:table”(以前从未听说过),以及非表格式的DIV(喜欢编写单词......)。
这是我创建的测试页面,用于测试三个并计算它们的时间(view it here):
<!--
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秒。所有与计时有关的代码都不会对它产生太大影响。您可以将其全部删除或全部注释(view it)并且它是相同的(对我来说是13,5和7)。
所以有两个问题:
首先,为什么这些数字存在差异?计时器应该计时函数中的所有内容。除了第一次调用updateDims之外,发生的两件事主要是字符串连接和innerHTML的赋值。 (网格的宽度也有变化,但我不知道这会花多少时间。)它是否只是浏览器渲染时间,一旦功能完成就会发生,所以没有定时?一些有利于此的证据是纯表格版本的显着时间要长得多,这意味着浏览器可能正在重新计算所有TD宽度等等。
其次,可以做些什么呢?什么?串联是它的一小部分,所以这不是问题。 (而且我已经尝试过进入阵列并加入,并且连接速度始终更快,至少对我而言。)此外,如果要相信秒表,将其插入innerHTML并不需要那么长时间。这是事后发生的一切。我曾经考虑过使用Backgrounder技术,所以即使需要一段时间来更新,至少它不会一直锁定浏览器,并且会发生一些明显的活动。但是如果锁定点发生在函数的“外部”,我看不出它是如何工作的。我可以设计自己的缩放功能,但我不相信它会比浏览器更快。初步测试说没有。
我正在尝试做的任何其他替代方案(虽然它可能对你很模糊;对不起)当然感激不尽!
StackOverflow上的其他一些页面:
Are large html tables slow?让人觉得桌子通常可以快速渲染。但是,这可能只适用于已经硬编码到HTML文件中的表,而不是像我的那样生成。
Javascript performance with creating large tables与我的情况非常相似,只是具有分页表的已接受解决方案对我来说不是一个选项,因为这会破坏目的。而我的表格不包含数据。然而,其中一位受访者确实暗示,使用如此庞大的表格,DOM方法可能比HTML解析更快(尽管我已经在其他地方看到反之亦然;可能含有大量元素)。当我有机会时,我可以测试一下。你觉得怎么样?