HTML 表格上的 Javascript/Jquery 过滤器效率极低

标签 javascript jquery html

我的意思是效率低下,激活代码会使页面挂起 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/

相关文章:

JavaScript:解码 PHP json_encode 响应

javascript - 基本 jquery .load

html - 如何在链接文本下对齐 Material 图标?

javascript - OpenLayers 3 - 亮点功能的 Z 索引

javascript - 在 innerHTML 中插入注释

javascript - HTML CSS 开/关按钮或记录器开关?

html - 将 <li> 文本与列表图像对齐

html - 我怎样才能让这个布局像它应该的那样对齐?

javascript - 如何在回调中访问正确的“this”?

javascript - 如何从 'click' 触发的函数获取返回值? Jquery JavaScript