我是一个Javascript新手。我写的代码是来自W3Schools的更新。
function sortFunctionNumeric(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("reportingTable");
switching = true;
//Set the sorting direction to ascending:
dir = "asc";
/*Make a loop that will continue until
no switching has been done:*/
while (switching) {
//start by saying: no switching is done:
switching = false;
rows = table.rows;
/*Loop through all table rows (except the
first, which contains table headers):*/
for (i = 1; i < (rows.length - 1); i++) {
//start by saying there should be no switching:
shouldSwitch = false;
/*Get the two elements you want to compare,
one from current row and one from the next:*/
x = rows[i].getElementsByTagName("TD")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
/*check if the two rows should switch place,
based on the direction, asc or desc:*/
if (dir == "asc") {
if (Number(x.innerHTML) > Number(y.innerHTML)) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
} else if (dir == "desc") {
if (Number(x.innerHTML) < Number(y.innerHTML)) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
/*If a switch has been marked, make the switch
and mark that a switch has been done:*/
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
//Each time a switch is done, increase this count by 1:
switchcount++;
} else {
/*If no switching has been done AND the direction is "asc",
set the direction to "desc" and run the while loop again.*/
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}现在,排序工作得非常好。然而,它是非常慢的!
我处理了很多daqta行(根据项目的不同,它可以高达9000行)。有没有办法加速我的Javascript代码?
发布于 2019-12-11 18:06:47
它有助于避免在浏览器JavaScript中实现排序算法,因为即使您最终实现了相同的排序算法,JavaScript内置的Array.prototype.sort方法也会快得多(IIRC大多数JS引擎可能都会使用QuickSort )。
我是这样做的:
Array中的所有<tr>元素。querySelectorAll与Array.from结合使用,因为querySelectorAll 不返回数组,它实际上返回一个NodeListOf<T> -但您可以将其传递到Array.from以将其转换为数组
Array,就可以使用带有自定义回调的Array.prototype.sort(comparison)从要比较的两个<tr>元素的<td>子元素中提取数据,然后进行数据比较(在比较数值时使用x - y技巧。对于string值,您将希望使用String.prototype.localeCompare,例如,对Array进行排序(即使对于包含数万行的表,这也不会超过几毫秒,as QuickSort is really quick!)使用父<tbody>.的appendChild重新添加每个<tr>
我在TypeScript中的实现如下所示,以及位于其下的脚本运行器中包含有效JavaScript的工作示例:
// This code has TypeScript type annotations, but can be used directly as pure JavaScript by just removing the type annotations first.
function sortTableRowsByColumn( table: HTMLTableElement, columnIndex: number, ascending: boolean ): void {
const rows = Array.from( table.querySelectorAll( ':scope > tbody > tr' ) );
rows.sort( ( x: HTMLtableRowElement, y: HTMLtableRowElement ) => {
const xValue: string = x.cells[columnIndex].textContent;
const yValue: string = y.cells[columnIndex].textContent;
// Assuming values are numeric (use parseInt or parseFloat):
const xNum = parseFloat( xValue );
const yNum = parseFloat( yValue );
return ascending ? ( xNum - yNum ) : ( yNum - xNum ); // <-- Neat comparison trick.
} );
// There is no need to remove the rows prior to adding them in-order because `.appendChild` will relocate existing nodes.
for( let row of rows ) {
table.tBodies[0].appendChild( row );
}
}
function onColumnHeaderClicked( ev: Event ): void {
const th = ev.currentTarget as HTMLTableCellElement;
const table = th.closest( 'table' );
const thIndex: number = Array.from( th.parentElement.children ).indexOf( th );
const ascending = ( th.dataset as any ).sort != 'asc';
sortTableRowsByColumn( table, thIndex, ascending );
const allTh = table.querySelectorAll( ':scope > thead > tr > th' );
for( let th2 of allTh ) {
delete th2.dataset['sort'];
}
th.dataset['sort'] = ascending ? 'asc' : 'desc';
}我的sortTableRowsByColumn函数假设如下:
<table>元素使用<thead>,并具有使用现代浏览器的单个<tbody>=>、Array.from、for( x of y )、:scope、.closest()和D53(即不是Internet Explorer11)。您的数据以D58的D56(D57)单元格的形式存在。表中没有D61或D62单元格。H263 F264这是一个可运行的示例。只需单击列标题即可按升序或降序进行排序:
function sortTableRowsByColumn( table, columnIndex, ascending ) {
const rows = Array.from( table.querySelectorAll( ':scope > tbody > tr' ) );
rows.sort( ( x, y ) => {
const xValue = x.cells[columnIndex].textContent;
const yValue = y.cells[columnIndex].textContent;
const xNum = parseFloat( xValue );
const yNum = parseFloat( yValue );
return ascending ? ( xNum - yNum ) : ( yNum - xNum );
} );
for( let row of rows ) {
table.tBodies[0].appendChild( row );
}
}
function onColumnHeaderClicked( ev ) {
const th = ev.currentTarget;
const table = th.closest( 'table' );
const thIndex = Array.from( th.parentElement.children ).indexOf( th );
const ascending = !( 'sort' in th.dataset ) || th.dataset.sort != 'asc';
const start = performance.now();
sortTableRowsByColumn( table, thIndex, ascending );
const end = performance.now();
console.log( "Sorted table rows in %d ms.", end - start );
const allTh = table.querySelectorAll( ':scope > thead > tr > th' );
for( let th2 of allTh ) {
delete th2.dataset['sort'];
}
th.dataset['sort'] = ascending ? 'asc' : 'desc';
}
window.addEventListener( 'DOMContentLoaded', function() {
const table = document.querySelector( 'table' );
const tb = table.tBodies[0];
const start = performance.now();
for( let i = 0; i < 9000; i++ ) {
let row = table.insertRow( -1 );
row.insertCell( -1 ).textContent = Math.ceil( Math.random() * 1000 );
row.insertCell( -1 ).textContent = Math.ceil( Math.random() * 1000 );
row.insertCell( -1 ).textContent = Math.ceil( Math.random() * 1000 );
}
const end = performance.now();
console.log( "IT'S OVER 9000 ROWS added in %d ms.", end - start );
} );html { font-family: sans-serif; }
table {
border-collapse: collapse;
border: 1px solid #ccc;
}
table > thead > tr > th {
cursor: pointer;
}
table > thead > tr > th[data-sort=asc] {
background-color: blue;
color: white;
}
table > thead > tr > th[data-sort=desc] {
background-color: red;
color: white;
}
table th,
table td {
border: 1px solid #bbb;
padding: 0.25em 0.5em;
}<table>
<thead>
<tr>
<th onclick="onColumnHeaderClicked(event)">Foo</th>
<th onclick="onColumnHeaderClicked(event)">Bar</th>
<th onclick="onColumnHeaderClicked(event)">Baz</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>9</td>
<td>a</td>
</tr>
<!-- 9,000 additional rows will be added by the DOMContentLoaded event-handler when this snippet is executed. -->
</tbody>
</table>
关于性能的一句话:
根据Chrome78的开发人员工具的性能分析器,在我的电脑上,performance.now()调用表明行在大约300ms内进行了排序,但是在JavaScript停止运行后发生的“重新计算样式”和“布局”操作分别花费了240ms和450ms (690ms的总重新布局时间,加上300ms的排序时间意味着从点击排序到排序需要整整一秒(1000ms))。
当我更改脚本,将<tr>元素添加到中间DocumentFragment而不是<tbody> (这样可以保证每个.appendChild调用都不会导致回流/布局,而不是仅仅假设.appendChild不会触发回流),并重新运行性能测试时,我的结果计时数字大致相同(5次重复后,它们实际上总共稍微高出约120ms,平均时间为1120ms)-但我会将其归因于浏览器即时播放。
下面是sortTableRowsByColumn中更改后的代码
function sortTableRowsByColumn( table, columnIndex, ascending ) {
const rows = Array.from( table.querySelectorAll( ':scope > tbody > tr' ) );
rows.sort( ( x, y ) => {
const xValue = x.cells[columnIndex].textContent;
const yValue = y.cells[columnIndex].textContent;
const xNum = parseFloat( xValue );
const yNum = parseFloat( yValue );
return ascending ? ( xNum - yNum ) : ( yNum - xNum );
} );
const fragment = new DocumentFragment();
for( let row of rows ) {
fragment.appendChild( row );
}
table.tBodies[0].appendChild( fragment );
}我认为性能相对较慢是因为自动的表格布局算法。我敢打赌,如果我把我的CSS改成使用table-layout: fixed;,布局时间就会缩短。(更新:我用table-layout: fixed;测试了它,令人惊讶的是,它根本没有提高性能-我似乎无法获得比1000ms更好的时间-哦,好吧)。
发布于 2019-12-11 20:34:48
<!DOCTYPE html>
<html>
<head>
<script>
function sort_table(tbody, index, sort = (a, b) => {
if(a < b) return -1; if(a > b) return 1; return 0;})
{
var list = []
for (var i = 0; i < tbody.children.length; i++)
list.push([tbody.children[i].children[index].innerText, tbody.children[i]]);
list.sort((a, b) => sort(a[0], b[0]));
var newtbody = document.createElement('tbody');
for (var i = 0; i < list.length; i++)
newtbody.appendChild(list[i][1]);
tbody.parentNode.replaceChild(newtbody, tbody);
return newtbody;
}
</script>
</head>
<body>
<h2>Unsorted</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Last Name</th>
<th>Nationality</th>
<th>Born</th>
</tr>
</thead>
<tbody>
<tr><td>Henry</td><td>Cavill</td>
<td>British</td><td>5 May 1983</td></tr>
<tr><td>Gal</td><td>Gadot</td>
<td>Israeli</td><td>30 April 1985</td></tr>
<tr><td>Olga</td><td>Kurylenko</td>
<td>Ukrainian</td><td>14 November 1979</td></tr>
<tr><td>Vincent</td><td>Cassel</td>
<td>French</td><td>23 November 1966</td></tr>
</tbody>
</table>
<script>
var table = document.getElementsByTagName('table')[0];
var named = table.cloneNode(true);
var dated = table.cloneNode(true);
document.body.innerHTML += "<h2>Sorted by name</h2>";
document.body.appendChild(named);
sort_table(named.children[1], 0); //by name
document.body.innerHTML += "<h2>Sorted by date</h2>";
document.body.appendChild(dated);
sort_table(dated.children[1], 3, (a, b) => { //by date
if (new Date(a) < new Date(b)) return -1;
if (new Date(a) > new Date(b)) return 1;
return 0;
});
</script>
</body>
</html>
156 ms - 190 ms中的9000行(数量)

发布于 2021-05-13 08:01:14
我需要根据一列地址对一个表进行排序:秋季街3号,布兰登路1号,自然巷10号,原始广场100号……想要的是街名和门牌号。
为此,我修改了sortTableRowsByContent函数,将数字从文本中分离出来。另外,因为我的一些列有空值,所以我在排序时隐藏它们:
function sortTableRowsByColumn( table, columnIndex, ascending ) {
const rows = Array.from( table.querySelectorAll( ':scope > tbody > tr' ) );
rows.sort( ( a, b ) => {
const aValue = a.cells[columnIndex].textContent;
const bValue = b.cells[columnIndex].textContent;
const aNum = parseFloat( aValue );
const bNum = parseFloat( bValue );
const aNew = aValue.replace(/^\d{1,3} /, "");
const bNew = bValue.replace(/^\d{1,3} /, "");
if (ascending){
return aNew.localeCompare(bNew) || parseInt(aNum) - parseInt(bNum);
} else {
return bNew.localeCompare(aNew) || parseInt(bNum) - parseInt(aNum);
}
} );
for ( i=0; i < rows.length; i++) {
if (rows[i].getElementsByTagName("td")[columnIndex].textContent == '') {
// this hides the blank rows
rows[i].style.display = "none";
} else {
// this restores blanks if a different column is sorted
rows[i].style.display = "";
}
};
for( let row of rows ) {
table.tBodies[0].appendChild( row );
}
}https://stackoverflow.com/questions/59282842
复制相似问题