Eu sou um novato em Javascript. Depois de experimentar muitos plug-ins Javascript e Jquery para classificar minha tabela HTML e acabar decepcionado, decidi implementar meu próprio código Javascript para classificar tabelas HTML. O código que escrevi é uma atualização do 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;
}
}
}
}
Agora a classificação funciona perfeitamente bem. No entanto, é muito lento!
Eu lido com muitas linhas de daqta (dependendo do projeto, ele pode ir até 9000 linhas). Existe uma maneira de acelerar meu código Javascript?
javascript
Lenin Mishra
fonte
fonte
document.createDocumentFragement()
O(n^2)
porque itera através da tabela para cada linha (ofor
interior dowhile
's). Use JavaScript built-in algoritmo de classificação emArray.prototype.sort
vez .sortFunctionNumeric
deve ser invocado? Están
destinado a ser o índice da coluna? (Observe que sua função falhará se houver umacolspan
ourowspan
na tabela).n
é o índice da coluna.Respostas:
Isso ajuda a evitar a implementação de algoritmos de classificação no JavaScript do navegador, porque o
Array.prototype.sort
método interno do JavaScript será muito mais rápido, mesmo se você acabar implementando o mesmo algoritmo de classificação (IIRC, a maioria dos mecanismos JS provavelmente usará o QuickSort de qualquer maneira).Aqui está como eu faria isso:
<tr>
elementos em um JavaScriptArray
.querySelectorAll
em conjunto com,Array.from
porquequerySelectorAll
não retorna uma matriz , na verdade, retornaNodeListOf<T>
- mas você pode passar issoArray.from
para convertê-lo em umArray
.Array
, você pode usarArray.prototype.sort(comparison)
com um retorno de chamada personalizado para extrair os dados do<td>
filho dos dois<tr>
elementos que estão sendo comparados e depois comparar os dados (usando ox - y
truque ao comparar valores numéricos. Parastring
valores que você deseja usarString.prototype.localeCompare
, por exemplo,return x.localeCompare( y )
.Array
ordenação (que não deve demorar mais do que alguns milissegundos até mesmo para uma tabela com dezenas de milhares de linhas, como o QuickSort é realmente rápido !), Adicione novamente cada<tr>
usoappendChild
do pai<tbody>
.Minha implementação no TypeScript está abaixo, juntamente com uma amostra funcional com JavaScript válido no script-runner localizado abaixo:
Minha
sortTableRowsByColumn
função assume o seguinte:<table>
elemento usa<thead>
e possui um único<tbody>
=>
,Array.from
,for( x of y )
,:scope
,.closest()
, e.remove()
(ou seja, não o Internet Explorer 11).#text
(.textContent
) dos<td>
elementos.colspan
ourowspan
células na tabela.Aqui está uma amostra executável. Basta clicar nos cabeçalhos das colunas para classificar em ordem crescente ou decrescente:
Uma palavra sobre desempenho:
De acordo com o analisador de desempenho das Ferramentas do desenvolvedor do Chrome 78, no meu computador, as
performance.now()
chamadas indicam que as linhas foram classificadas em cerca de 300ms; no entanto, as operações "Recalcular estilo" e "Layout", que acontecem depois que o JavaScript parou de executar, demoraram 240ms e 450ms, respectivamente ( O tempo total de retransmissão de 690 ms, mais o tempo de classificação de 300 ms, levaram um segundo inteiro (1.000 ms) do clique para a classificação).Quando mudei o script, de modo que os
<tr>
elementos sejam adicionados a um intermediário emDocumentFragment
vez de<tbody>
(para que cada.appendChild
chamada seja garantida para não causar um reflow / layout, em vez de apenas presumir que.appendChild
não causará um reflow) e refiz a performance teste meus números de cronometragem de resultados eram mais ou menos idênticos (na verdade, eram um pouco mais altos em cerca de 120ms no total após 5 repetições, por um tempo médio de (1.120ms) - mas vou colocar isso na reprodução do JIT do navegador .Aqui está o código alterado dentro
sortTableRowsByColumn
:Eu acho que o desempenho é relativamente lento devido ao algoritmo de layout de tabela automático. Aposto que se eu mudar meu CSS para usar
table-layout: fixed;
o layout, os tempos diminuirão. (Atualização: eu testeitable-layout: fixed;
e surpreendentemente isso não melhorou o desempenho - parece que não consigo obter tempos melhores que 1.000ms - tudo bem).fonte
.remove()
. Basta anexá-los..appendChild
isso moverá um elemento.onclick
para todas as colunas? Por exemplo, a terceira coluna não está sendo classificada. Então eu não tenho que incluironclick
nessa coluna .. certo?onclick
é apenas a mais simples. Você também pode usar.addEventListener('click', onColumnHeaderClicked )
dentro de um script nos objetos de elemento que também deseja usar.performance.now()
chamadas para medir e classifica por 9000 linhas em cerca de 300ms na minha área de trabalho (Chrome 78 x64 no Core i7 6850K). Vou tentar sua sugestão para usarDocumentFragment
agora.9000 linhas (números) em 156 ms - 190 ms
fonte