效率低下我的意思是,激活代码会使页面挂起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>
给出用户的过滤器如下:
我写过的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/)。< / p>
答案 0 :(得分:3)
目前您的代码的工作方式如下:
仅关于上述暴露机制并使用您引用的某些数字意味着,使用像#34;团队&#34;这样的独特简单过滤器。你实际上触摸了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!
这可以通过影响这些相关列的区分类(比如filter-name)来实现,所以我们可能会改变这样的代码:
$("#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
可能存在此问题:
它是从Python / Flask生成的静态HTML表格
这意味着你没有掌握生成的表格 如果是这样,您只需添加以下内容即可在页面加载后影响类名称:
$(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();
}
}
}
这写得有点快,所以它可能包含一些缺陷,也可能会有所改进......
答案 1 :(得分:1)
您可以通过缓存重复使用的元素并减少迭代次数来改进代码。目前,您可以对记录进行三次迭代,这些记录可以压缩为一个。
这是我将如何做到的(未经测试):
$(function () {
// cache the elements that you will be re-using
var $minGP = $("#mingp"),
$team = $("#teamFilter"),
$position = $("#position"),
$age = $("#age");
var $rows = $("#myTablePlayers .playerData");
function filterTable() {
// Need some error checking on input not number
var minGP = $minGP.val(),
team = $team.val(),
position = $position.val(),
age = $age.val();
// set the rank as we loop (instead of having a separate iteration for ranking)
var rank = 0;
// when you use show() and .each(), you are iterating over all the rows twice
// instead loop once
$rows.each(function() {
// cache current row as it will be re-used
var $row = $(this);
// set flag to show or hide
var display = true;
if (teams != "" &&
!$row.find('td').eq(colTeam).text().toUpperCase().indexOf(teams.toUpperCase()) > -1) {
display = false;
}
if (Number($row.find('td').eq(colGP).text()) < minGP) {
display = false;
}
if (position != "") {
if (position == "D" &&
$row.find('td').eq(colPos).text().indexOf("D") == -1) {
display = false;
} else if (position == "F" &&
$row.find('td').eq(colPos).text().indexOf("D") != -1) {
display = false;
} else if ($row.find('td').eq(colPos).text() != position) {
display = false;
}
}
if (age != "") {
column = Number($row.find('td').eq(colAge).text())
age = Number(age)
if (column < age || column >= age + 1) {
display = false;
}
}
// hide or show row
$tr.toggle(display);
// set rank number
if (display) {
$row.find('td').eq(colRank).text(rank++);
}
});
}
// attach change event handler
$minGP.add($team).add($position).add($age).change(filterTable);
});
这可能会使您的代码加速几秒钟,但最终取决于您的数据的数量和大小。