我的意思是效率低下,激活代码会使页面挂起 20 秒以上。
为了设置场景,我当前有一个如下所示的 HTML 表格。它可以相当大,很容易有 1,000-1,500 行和 40 列宽。它是从 Python/Flask 生成的静态 HTML 表,然后由 javascript 接管以允许用户过滤和排序行。我确实使用 jquery tablesorter 小部件来允许用户按他们希望的任何列对行进行排序。
表本身的结构如下:
<table id="myTablePlayers" class="tablesorter table table-striped table-bordered table-hover" style="overflow: visible">
<thead>
<tr>
<th>...</th>
<th>...</th>
<th>...</th>
<th>...</th>
...
<th>...</th>
</tr>
</thead>
<tbody>
<tr class="playerData">
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
...
<td>...</td>
</tr>
...
</tbody>
</table>
给用户的过滤器如下:
- 最小 GP - 输入字段,删除特定列中小于用户输入的所有行
- 团队 - 选择字段(文本),删除特定列中不匹配的所有行
- 位置 - 选择字段(文本),删除特定列中不匹配的所有行
- 年龄 - 输入字段,删除特定列中小于用户输入的所有行(例如,如果输入 20,它将保留年龄在 [20.0, 21.0)范围内的所有行
我编写的 javascript/jquery 可能是罪魁祸首如下:
function autoRank() {
// auto number
rank = 0;
$("#myTablePlayers .playerData").each(function() {
if ($(this).css("display") != "none") {
rank++;
$(this).find('td').eq(colRank).text(rank);
}
});
}
function filterTable() {
// Need some error checking on input not number
minGP = $("#mingp").val()
teams = $("#teamFilter").val()
position = $("#position").val()
age = $("#age").val()
$("#myTablePlayers .playerData").show();
$("#myTablePlayers .playerData").each(function() {
toHide = false;
if (teams != "") {
if ( !$(this).find('td').eq(colTeam).text().toUpperCase().includes(teams.toUpperCase())) {
toHide = true;
}
}
if ( Number($(this).find('td').eq(colGP).text()) < minGP ) {
toHide = true;
}
if (position != "") {
if (position == "D") {
if ($(this).find('td').eq(colPos).text().indexOf("D") == -1) {
toHide = true;
}
} else if (position == "F") {
if ($(this).find('td').eq(colPos).text().indexOf("D") != -1) {
toHide = true;
}
} else if ( $(this).find('td').eq(colPos).text() != position) {
toHide = true;
}
}
if (age != "") {
column = Number($(this).find('td').eq(colAge).text())
age = Number(age)
if ( column < age || column >= age+1 ) {
toHide = true;
}
}
if (toHide == true) {
$(this).hide();
}
});
autoRank();
}
$("#teamFilter").on('change', filterTable);
$("#mingp").on('change', filterTable);
$("#position").on('change', filterTable);
$("#age").on('change', filterTable);
这段代码的低效率是什么导致浏览器挂起?我应该改变什么才能提高效率?
我查看了 Google,但 jquery 表过滤器 插件无法让我能够根据上述特定输入(例如 https://www.sitepoint.com/12-amazing-jquery-tables/ )根据特定列过滤行。
最佳答案
目前您的代码的工作原理如下:
- 迭代所有行
- 然后对于每一行:
- 依次针对每个非空过滤器查找其所有子列
- 然后隔离涉及的列并获取其值
仅考虑上述公开的机制并使用您引用的一些数字,这意味着,使用像“团队”这样独特的简单过滤器,您实际上接触了 40000 列(1000 行 * 1 个过滤器 * 40 列)。
但如果 2 个过滤器非空,它会立即增长到 80000 列,依此类推。
这显然是找到一种更快工作方式的第一个领域,只需进行如下非常简单的更改即可:
- 迭代所有行
- 然后对于每一行:
- 查找其所有子列
- 依次针对每个非空过滤器,然后隔离涉及的列并获取其值
涉及的代码部分变为:
$("#myTablePlayers .playerData").each(function() {
var toHide = false,
columns = $(this).find('td');
if (teams != "") {
if ( !columns.eq(colTeam).text().toUpperCase().includes(teams.toUpperCase())) {
toHide = true;
}
}
// ...same for next filters
这样,我们就不再需要将列接触次数乘以非空过滤器的数量了。
但我们可以走得更远...
在当前情况下,每次执行实际上涉及表的所有单元格,而最多涉及 4 列(对于 4 个过滤器)。所以我们可能会尝试找到一种方法将触摸列的总数从 40000 减少到 4000!
这可以通过影响这些涉及的列的区别类(例如过滤器名称)来实现,因此我们可以像这样更改代码:
$("#myTablePlayers .playerData").each(function() {
var toHide = false,
classTeam = '.colTeam',
classGP = `.colGP`,
classPos = `.colPos`,
classAge = `.colAge`;
if (teams != "") {
if ( !$(classTeam, this).text().toUpperCase().includes(teams.toUpperCase())) {
toHide = true;
}
}
// ...same for next filters
也许这有问题:
It is generated from Python/Flask as a static HTML table
这意味着您无法控制生成的表。
如果是这样,您只需添加以下内容即可在页面加载后影响类名称:
$(document).ready(function() {
$("#myTablePlayers .playerData").each(function() {
$('td', this).eq(colTeam).addClass(classTeam);
$('td', this).eq(colGP).addClass(classGP);
// ...
}
}
但实际上它可能会以另一种方式改进(那么之前的建议就变得毫无用处),使用完全不同的方法。
由于表是静态的,我们可以在页面加载后立即采取行动(因此仅一次)来准备所需的数据,以便在过滤发生时进行更直接的访问。
我们可以为每个过滤器预先注册所有涉及的列:
$(document).ready(function() {
var teamCols = $(),
GPCols = $(),
posCols = $(),
ageCols = $();
$("#myTablePlayers .playerData").each(function() {
var columns = $(this).find('td');
teamCols.add(columns.eq(colTeam));
GPCols.add(columns.eq(colGP));
posCols.add(columns.eq(colPos));
ageCols.add(columns.eq(colAge));
}
}
然后过滤器可以直接处理涉及的列。顺便说一句,我们还可以立即隐藏它们的父级(这在原始版本中已经可以实现):
if (teams) {
teamCols.each(function() {
if (!this.innerHTML.toUpperCase().includes(teams.toUpperCase())) {
$(this).parent().hide();
}
}
}
写得有点快,所以可能有一些缺陷,也可能还有待改进......
关于HTML 表格上的 Javascript/Jquery 过滤器效率极低,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40835272/