WebUI: Improve performance of re-sorting table rows

This change drastically improves the performance of changing a table's sorted column. This performance is achieved through improved data structures, namely removing operations that repeatedly spliced an array. We also no longer iterate over a potentially large array.

On a torrent with ~50,000 files, re-rendering after a sort improves from ~20 seconds to 2 seconds.

PR #22827.
This commit is contained in:
Thomas Piccirello 2025-06-14 06:06:33 -07:00 committed by GitHub
parent d7a5430893
commit 406a389d7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -858,42 +858,49 @@ window.qBittorrent.DynamicTable ??= (() => {
}
else {
const trs = [...this.getTrs()];
const trMap = new Map(trs.map(tr => [tr.rowId, tr]));
for (let rowPos = 0; rowPos < rows.length; ++rowPos) {
const rowId = rows[rowPos].rowId;
let tr_found = false;
for (let j = rowPos; j < trs.length; ++j) {
if (trs[j].rowId === rowId) {
tr_found = true;
if (rowPos === j)
break;
trs[j].inject(trs[rowPos], "before");
const tmpTr = trs[j];
trs.splice(j, 1);
trs.splice(rowPos, 0, tmpTr);
break;
}
const existingTr = trMap.get(rowId);
if (existingTr !== undefined) {
this.updateRow(existingTr, fullUpdate);
}
if (tr_found) { // row already exists in the table
this.updateRow(trs[rowPos], fullUpdate);
}
else { // else create a new row in the table
else {
const tr = this.createRowElement(rows[rowPos]);
// Insert
if (rowPos >= trs.length) {
tr.inject(this.tableBody);
trs.push(tr);
}
else {
tr.inject(trs[rowPos], "before");
trs.splice(rowPos, 0, tr);
}
// TODO look into using DocumentFragment or appending all trs at once for add'l performance gains
// add to end of table - we'll move into the proper order later
this.tableBody.appendChild(tr);
trMap.set(rowId, tr);
this.updateRow(tr, true);
}
}
// reorder table rows
let prevTr = null;
for (let rowPos = 0; rowPos < rows.length; ++rowPos) {
const { rowId } = rows[rowPos];
const tr = trMap.get(rowId);
const isInCorrectLocation = rowId === trs[rowPos]?.rowId;
if (!isInCorrectLocation) {
// move row into correct location
if (prevTr === null) {
// insert as first row in table
if (trs.length === 0)
this.tableBody.append(tr);
else
trs[0].before(tr);
}
else {
prevTr.after(tr);
}
}
prevTr = tr;
}
const rowPos = rows.length;
while ((rowPos < trs.length) && (trs.length > 0))