Soy un novato en Javascript. Después de probar muchos complementos de Javascript y Jquery para ordenar mi tabla HTML y terminar decepcionado, decidí implementar mi propio código Javascript para ordenar las tablas HTML. El código que escribí es una actualización de 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;
}
}
}
}
Ahora la clasificación funciona perfectamente bien. ¡Sin embargo, es muy lento!
Trato con muchas filas de daqta (dependiendo del proyecto, puede subir hasta 9000 filas). ¿Hay alguna manera de acelerar mi código Javascript?
javascript
Lenin Mishra
fuente
fuente
document.createDocumentFragement()
O(n^2)
porque itera a través de la tabla para cada fila (elfor
interiorwhile
). Utilice el algoritmo de ordenación incorporado de JavaScript en suArray.prototype.sort
lugar .sortFunctionNumeric
supone que debes ser invocado? ¿Están
destinado a ser el índice de la columna? (Observo que su función fallará si hay uncolspan
orowspan
en la tabla).n
es el índice de la columna.Respuestas:
Ayuda a evitar la implementación de algoritmos de clasificación en JavaScript del navegador porque el
Array.prototype.sort
método incorporado de JavaScript será mucho más rápido incluso si termina implementando el mismo algoritmo de clasificación (IIRC la mayoría de los motores JS probablemente usarán QuickSort de todos modos).Así es como lo haría:
<tr>
elementos en un JavaScriptArray
.querySelectorAll
junto conArray.from
porquequerySelectorAll
no devuelve una matriz , en realidad devuelve unNodeListOf<T>
- pero puede pasar estoArray.from
a convertirlo en unArray
.Array
, puede usarloArray.prototype.sort(comparison)
con una devolución de llamada personalizada para extraer los datos del elemento<td>
secundario de los dos<tr>
elementos que se están comparando, y luego comparar los datos (usando elx - y
truco al comparar valores numéricos. Para losstring
valores que querrá usarString.prototype.localeCompare
, p. Ej.return x.localeCompare( y )
.Array
se ordena (lo que no debería tomar más de unos pocos milisegundos incluso para una tabla con decenas de miles de filas, ¡ ya que QuickSort es realmente rápido !) Vuelva a agregar cada<tr>
usoappendChild
del padre<tbody>
.Mi implementación en TypeScript está a continuación, junto con una muestra de trabajo con JavaScript válido en el script-runner ubicado debajo:
Mi
sortTableRowsByColumn
función asume lo siguiente:<table>
elemento usa<thead>
y tiene un solo<tbody>
=>
,Array.from
,for( x of y )
,:scope
,.closest()
, y.remove()
(es decir, no Internet Explorer 11).#text
(.textContent
) de los<td>
elementos.colspan
orowspan
celdas en la tabla.Aquí hay una muestra ejecutable. Simplemente haga clic en los encabezados de columna para ordenar en orden ascendente o descendente:
Una palabra sobre el rendimiento:
De acuerdo con el analizador de rendimiento de Developer Tools de Chrome 78, en mi computadora, las
performance.now()
llamadas indican que las filas se ordenaron en aproximadamente 300 ms, sin embargo, las operaciones de "Recalcular estilo" y "Diseño" que ocurren después de que JavaScript dejó de funcionar tomaron 240 ms y 450 ms respectivamente ( El tiempo total de retransmisión de 690 ms, más el tiempo de clasificación de 300 ms significa que tomó un segundo completo (1,000 ms) desde hacer clic para ordenar).Cuando cambié el script de tal manera que los
<tr>
elementos se agregan a un intermedio enDocumentFragment
lugar del<tbody>
(para que.appendChild
se garantice que cada llamada no cause un reflujo / diseño, en lugar de suponer que.appendChild
eso no desencadenará un reflujo) y volvió a ejecutar el rendimiento probar las cifras de tiempo de resultados fueron más o menos idénticas (en realidad fueron un poco más altas en aproximadamente 120 ms en total después de 5 repeticiones, durante un tiempo promedio de (1.120 ms), pero lo atribuiré a la reproducción JIT del navegador .Aquí está el código cambiado dentro
sortTableRowsByColumn
:Creo que el rendimiento es relativamente lento debido al algoritmo de diseño automático de tabla. Apuesto a que si cambio mi CSS para usar,
table-layout: fixed;
los tiempos de diseño se reducirán. (Actualización: lo probétable-layout: fixed;
y, sorprendentemente, eso no mejoró el rendimiento en absoluto; parece que no puedo obtener mejores tiempos que 1,000 ms, oh, bueno).fuente
.remove()
. Solo añádelos..appendChild
moverá un elemento.onclick
para todas las columnas? Por ejemplo, la tercera columna no se está ordenando. Así que no tengo que incluironclick
para esa columna ... ¿verdad?onclick
es la más simple. También puede usar.addEventListener('click', onColumnHeaderClicked )
dentro de un script en los objetos de elementos que desea usar también.performance.now()
llamadas para medir y se clasifica a través de 9000 filas en aproximadamente 300 ms en mi escritorio (Chrome 78 x64 en Core i7 6850K). Probaré tu sugerencia para usarDocumentFragment
ahora.9000 filas (números) en 156 ms - 190 ms
fuente