Ich bin ein Javascript-Neuling. Nachdem ich viele Javascript- und Jquery-Plugins zum Sortieren meiner HTML-Tabelle ausprobiert hatte und enttäuscht war, entschied ich mich, meinen eigenen Javascript-Code zum Sortieren von HTML-Tabellen zu implementieren. Der Code, den ich geschrieben habe, ist ein Update von 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;
}
}
}
}
Jetzt funktioniert die Sortierung einwandfrei. Es ist jedoch sehr langsam!
Ich beschäftige mich mit vielen Daqta-Zeilen (je nach Projekt können es bis zu 9000 Zeilen sein). Gibt es eine Möglichkeit, meinen Javascript-Code zu beschleunigen?
javascript
Lenin Mishra
quelle
quelle
document.createDocumentFragement()
O(n^2)
da es die Tabelle für jede Zeile (for
innerhalb derwhile
) durchläuft . Verwenden SieArray.prototype.sort
stattdessen den in JavaScript integrierten Sortieralgorithmus bei .sortFunctionNumeric
man angerufen werden? Solln
der Spaltenindex sein? (Ich stelle fest, dass Ihre Funktion fehlschlägt, wenn eincolspan
oderrowspan
in der Tabelle vorhanden ist).n
ist der Spaltenindex.Antworten:
Es hilft, die Implementierung von Sortieralgorithmen in Browser-JavaScript zu vermeiden, da die in JavaScript integrierte
Array.prototype.sort
Methode viel schneller ist, selbst wenn Sie am Ende denselben Sortieralgorithmus implementieren (IIRC, die meisten JS-Engines werden wahrscheinlich sowieso QuickSort verwenden ).So würde ich es machen:
<tr>
Elemente in einem JavaScriptArray
.querySelectorAll
in Verbindung mit verwenden,Array.from
weilquerySelectorAll
kein Array zurückgegeben wird , sondern tatsächlich einNodeListOf<T>
- aber Sie können dies übergebenArray.from
, um es in ein zu konvertierenArray
.Array
, können SieArray.prototype.sort(comparison)
mit einem benutzerdefinierten Rückruf die Daten aus dem<td>
untergeordneten<tr>
Element der beiden zu vergleichenden Elemente extrahieren und dann die Daten vergleichen (mit demx - y
Trick beim Vergleichen numerischer Werte. Fürstring
Werte, die Sie verwenden möchtenString.prototype.localeCompare
, zreturn x.localeCompare( y )
.Array
sortiert wird (was nicht mehr als ein paar Millisekunden auch nur für einen Tisch mit Zehntausenden von Zeilen, nehmen sollten als QuickSort ist wirklich schnell !) Wieder jede weitere<tr>
VerwendungappendChild
der Mutter<tbody>
.Meine Implementierung in TypeScript ist unten zusammen mit einem Arbeitsbeispiel mit gültigem JavaScript im Skript-Runner unten aufgeführt:
Meine
sortTableRowsByColumn
Funktion setzt Folgendes voraus:<table>
Element verwendet<thead>
und hat eine einzige<tbody>
=>
,Array.from
,for( x of y )
,:scope
,.closest()
, und.remove()
(also nicht den Internet Explorer 11).#text
(.textContent
) der<td>
Elemente.colspan
oderrowspan
mehrere Zellen.Hier ist ein lauffähiges Beispiel. Klicken Sie einfach auf die Spaltenüberschriften, um sie in aufsteigender oder absteigender Reihenfolge zu sortieren:
Ein Wort zur Leistung:
Laut dem Performance Analyzer von Developer Tools von Chrome 78 auf meinem Computer zeigen die
performance.now()
Aufrufe an, dass die Zeilen in etwa 300 ms sortiert wurden. Die Vorgänge "Stil neu berechnen" und "Layout", die ausgeführt werden, nachdem JavaScript nicht mehr ausgeführt wird, dauerten 240 ms bzw. 450 ms ( Die gesamte Relayout-Zeit von 690 ms plus die Sortierzeit von 300 ms bedeutet, dass es eine volle Sekunde (1.000 ms) vom Klicken zum Sortieren gedauert hat.Wenn ich das Skript so geändert habe, dass die
<tr>
Elemente zu einem ZwischenproduktDocumentFragment
anstelle von hinzugefügt werden<tbody>
(so dass jeder.appendChild
Aufruf garantiert keinen Reflow / Layout verursacht, anstatt nur davon auszugehen, dass dies.appendChild
keinen Reflow auslöst) und die Leistung erneut ausgeführt habe Testen Sie mein Ergebnis. Die Timing-Zahlen waren mehr oder weniger identisch (sie waren nach 5 Wiederholungen für eine durchschnittliche Zeit von (1.120 ms) tatsächlich um etwa 120 ms etwas höher - aber ich werde das auf die JIT-Wiedergabe des Browsers zurückführen .Hier ist der geänderte Code
sortTableRowsByColumn
:Ich denke, die Leistung ist aufgrund des automatischen Tabellenlayout-Algorithmus relativ langsam. Ich wette, wenn ich mein CSS ändere, um
table-layout: fixed;
die Layoutzeiten zu verwenden, werden sie kürzer. (Update: Ich habe es getestettable-layout: fixed;
und überraschenderweise hat das die Leistung überhaupt nicht verbessert - ich kann anscheinend keine besseren Zeiten als 1.000 ms erreichen - na ja).quelle
.remove()
. Fügen Sie sie einfach hinzu..appendChild
ein Element bewegen wird.onclick
für alle Spalten einschließen ? Beispielsweise wird die dritte Spalte nicht sortiert. Also muss ichonclick
für diese Spalte nicht einfügen .. richtig?onclick
ist einfach die einfachste. Sie können auch.addEventListener('click', onColumnHeaderClicked )
innerhalb eines Skripts die Elementobjekte verwenden, die Sie ebenfalls verwenden möchten.performance.now()
Aufrufe zum Messen hinzugefügt und es sortiert 9000 Zeilen in ca. 300 ms auf meinem Desktop (Chrome 78 x64 auf Core i7 6850K). Ich werde versuchen, Ihren VorschlagDocumentFragment
jetzt zu verwenden .9000 Zeilen (Zahlen) in 156 ms - 190 ms
quelle