WebUI: avoid redundant operations when sorting

Avoid recomputing the same result on every sort operation.
Also clean up the caller site.

PR #22821.
This commit is contained in:
Chocobo1 2025-06-08 17:08:47 +08:00 committed by GitHub
parent 8e2125ee72
commit 4132173b30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -829,13 +829,11 @@ window.qBittorrent.DynamicTable ??= (() => {
filteredRows[row.rowId] = row; filteredRows[row.rowId] = row;
} }
const column = this.columns[this.sortedColumn];
const isReverseSort = (this.reverseSort === "0");
filteredRows.sort((row1, row2) => { filteredRows.sort((row1, row2) => {
const column = this.columns[this.sortedColumn]; const result = column.compareRows(row1, row2);
const res = column.compareRows(row1, row2); return isReverseSort ? result : -result;
if (this.reverseSort === "0")
return res;
else
return -res;
}); });
return filteredRows; return filteredRows;
} }
@ -1777,13 +1775,11 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
} }
const column = this.columns[this.sortedColumn];
const isReverseSort = (this.reverseSort === "0");
filteredRows.sort((row1, row2) => { filteredRows.sort((row1, row2) => {
const column = this.columns[this.sortedColumn]; const result = column.compareRows(row1, row2);
const res = column.compareRows(row1, row2); return isReverseSort ? result : -result;
if (this.reverseSort === "0")
return res;
else
return -res;
}); });
return filteredRows; return filteredRows;
} }
@ -2037,13 +2033,11 @@ window.qBittorrent.DynamicTable ??= (() => {
filteredRows = [...this.getRowValues()]; filteredRows = [...this.getRowValues()];
} }
const column = this.columns[this.sortedColumn];
const isReverseSort = (this.reverseSort === "0");
filteredRows.sort((row1, row2) => { filteredRows.sort((row1, row2) => {
const column = this.columns[this.sortedColumn]; const result = column.compareRows(row1, row2);
const res = column.compareRows(row1, row2); return isReverseSort ? result : -result;
if (this.reverseSort === "0")
return res;
else
return -res;
}); });
return filteredRows; return filteredRows;
@ -2454,26 +2448,31 @@ window.qBittorrent.DynamicTable ??= (() => {
this.updateGlobalCheckbox(); this.updateGlobalCheckbox();
} }
#sortNodesByColumn(nodes, column) { #sortNodesByColumn(root, column) {
nodes.sort((row1, row2) => { const isColumnOriginal = (column.name === "original");
// list folders before files when sorting by name const isReverseSort = (this.reverseSort === "0");
if (column.name === "original") {
const node1 = this.getNode(row1.data.rowId);
const node2 = this.getNode(row2.data.rowId);
if (node1.isFolder && !node2.isFolder)
return -1;
if (node2.isFolder && !node1.isFolder)
return 1;
}
const res = column.compareRows(row1, row2); const stack = [root];
return (this.reverseSort === "0") ? res : -res; while (stack.length > 0) {
}); const node = stack.pop();
nodes.each((node) => { node.children.sort((row1, row2) => {
if (node.children.length > 0) // list folders before files when sorting by name
this.#sortNodesByColumn(node.children, column); if (isColumnOriginal) {
}); const node1 = this.getNode(row1.data.rowId);
const node2 = this.getNode(row2.data.rowId);
if (node1.isFolder && !node2.isFolder)
return -1;
if (!node1.isFolder && node2.isFolder)
return 1;
}
const result = column.compareRows(row1, row2);
return isReverseSort ? result : -result;
});
stack.push(...node.children);
}
} }
#filterNodes(root, filterTerms) { #filterNodes(root, filterTerms) {
@ -2532,7 +2531,8 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
getFilteredAndSortedRows() { getFilteredAndSortedRows() {
if (this.getRoot() === null) const root = this.getRoot();
if (root === null)
return []; return [];
const generateRowsSignature = () => { const generateRowsSignature = () => {
@ -2542,16 +2542,6 @@ window.qBittorrent.DynamicTable ??= (() => {
return JSON.stringify(rowsData); return JSON.stringify(rowsData);
}; };
const getFilteredRows = () => {
if (this.filterTerms.length === 0) {
const nodeArray = this.fileTree.toArray();
const filteredRows = nodeArray.map(node => this.getRow(node));
return filteredRows;
}
return this.#filterNodes(this.getRoot().children[0], this.filterTerms);
};
const hasRowsChanged = function(rowsString, prevRowsStringString) { const hasRowsChanged = function(rowsString, prevRowsStringString) {
const rowsChanged = (rowsString !== prevRowsStringString); const rowsChanged = (rowsString !== prevRowsStringString);
const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => { const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => {
@ -2570,16 +2560,23 @@ window.qBittorrent.DynamicTable ??= (() => {
return this.prevFilteredRows; return this.prevFilteredRows;
// sort, then filter // sort, then filter
const column = this.columns[this.sortedColumn]; this.#sortNodesByColumn(root, this.columns[this.sortedColumn]);
this.#sortNodesByColumn(this.getRoot().children, column); const rows = (() => {
const filteredRows = getFilteredRows(); if (this.filterTerms.length === 0) {
const nodeArray = this.fileTree.toArray();
const filteredRows = nodeArray.map(node => this.getRow(node));
return filteredRows;
}
return this.#filterNodes(root.children[0], this.filterTerms);
})();
this.prevFilterTerms = this.filterTerms; this.prevFilterTerms = this.filterTerms;
this.prevRowsString = rowsString; this.prevRowsString = rowsString;
this.prevFilteredRows = filteredRows; this.prevFilteredRows = rows;
this.prevSortedColumn = this.sortedColumn; this.prevSortedColumn = this.sortedColumn;
this.prevReverseSort = this.reverseSort; this.prevReverseSort = this.reverseSort;
return filteredRows; return rows;
} }
setIgnored(rowId, ignore) { setIgnored(rowId, ignore) {
@ -2917,26 +2914,31 @@ window.qBittorrent.DynamicTable ??= (() => {
this.columns["availability"].updateTd = displayPercentage; this.columns["availability"].updateTd = displayPercentage;
} }
#sortNodesByColumn(nodes, column) { #sortNodesByColumn(root, column) {
nodes.sort((row1, row2) => { const isColumnName = (column.name === "name");
// list folders before files when sorting by name const isReverseSort = (this.reverseSort === "0");
if (column.name === "name") {
const node1 = this.getNode(row1.data.rowId);
const node2 = this.getNode(row2.data.rowId);
if (node1.isFolder && !node2.isFolder)
return -1;
if (node2.isFolder && !node1.isFolder)
return 1;
}
const res = column.compareRows(row1, row2); const stack = [root];
return (this.reverseSort === "0") ? res : -res; while (stack.length > 0) {
}); const node = stack.pop();
nodes.each((node) => { node.children.sort((row1, row2) => {
if (node.children.length > 0) // list folders before files when sorting by name
this.#sortNodesByColumn(node.children, column); if (isColumnName) {
}); const node1 = this.getNode(row1.data.rowId);
const node2 = this.getNode(row2.data.rowId);
if (node1.isFolder && !node2.isFolder)
return -1;
if (!node1.isFolder && node2.isFolder)
return 1;
}
const result = column.compareRows(row1, row2);
return isReverseSort ? result : -result;
});
stack.push(...node.children);
}
} }
#filterNodes(root, filterTerms) { #filterNodes(root, filterTerms) {
@ -2995,7 +2997,8 @@ window.qBittorrent.DynamicTable ??= (() => {
} }
getFilteredAndSortedRows() { getFilteredAndSortedRows() {
if (this.getRoot() === null) const root = this.getRoot();
if (root === null)
return []; return [];
const generateRowsSignature = () => { const generateRowsSignature = () => {
@ -3005,8 +3008,6 @@ window.qBittorrent.DynamicTable ??= (() => {
return JSON.stringify(rowsData); return JSON.stringify(rowsData);
}; };
const getFilteredRows = () => this.#filterNodes(this.getRoot().children[0], this.filterTerms);
const hasRowsChanged = function(rowsString, prevRowsStringString) { const hasRowsChanged = function(rowsString, prevRowsStringString) {
const rowsChanged = (rowsString !== prevRowsStringString); const rowsChanged = (rowsString !== prevRowsStringString);
const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => { const isFilterTermsChanged = this.filterTerms.reduce((acc, term, index) => {
@ -3025,16 +3026,15 @@ window.qBittorrent.DynamicTable ??= (() => {
return this.prevFilteredRows; return this.prevFilteredRows;
// sort, then filter // sort, then filter
const column = this.columns[this.sortedColumn]; this.#sortNodesByColumn(root, this.columns[this.sortedColumn]);
this.#sortNodesByColumn(this.getRoot().children, column); const rows = this.#filterNodes(root.children[0], this.filterTerms);
const filteredRows = getFilteredRows();
this.prevFilterTerms = this.filterTerms; this.prevFilterTerms = this.filterTerms;
this.prevRowsString = rowsString; this.prevRowsString = rowsString;
this.prevFilteredRows = filteredRows; this.prevFilteredRows = rows;
this.prevSortedColumn = this.sortedColumn; this.prevSortedColumn = this.sortedColumn;
this.prevReverseSort = this.reverseSort; this.prevReverseSort = this.reverseSort;
return filteredRows; return rows;
} }
setIgnored(rowId, ignore) { setIgnored(rowId, ignore) {
@ -3603,10 +3603,11 @@ window.qBittorrent.DynamicTable ??= (() => {
filteredRows = [...this.getRowValues()]; filteredRows = [...this.getRowValues()];
} }
const column = this.columns[this.sortedColumn];
const isReverseSort = (this.reverseSort === "0");
filteredRows.sort((row1, row2) => { filteredRows.sort((row1, row2) => {
const column = this.columns[this.sortedColumn]; const result = column.compareRows(row1, row2);
const res = column.compareRows(row1, row2); return isReverseSort ? result : -result;
return (this.reverseSort === "0") ? res : -res;
}); });
this.filteredLength = filteredRows.length; this.filteredLength = filteredRows.length;
@ -3661,10 +3662,11 @@ window.qBittorrent.DynamicTable ??= (() => {
filteredRows = [...this.getRowValues()]; filteredRows = [...this.getRowValues()];
} }
const column = this.columns[this.sortedColumn];
const isReverseSort = (this.reverseSort === "0");
filteredRows.sort((row1, row2) => { filteredRows.sort((row1, row2) => {
const column = this.columns[this.sortedColumn]; const result = column.compareRows(row1, row2);
const res = column.compareRows(row1, row2); return isReverseSort ? result : -result;
return (this.reverseSort === "0") ? res : -res;
}); });
return filteredRows; return filteredRows;