【问题标题】:What's the fastest way to select a large amount of checkboxes and de/select them?选择大量复选框并取消/选择它们的最快方法是什么?
【发布时间】:2020-01-24 12:51:15
【问题描述】:

自从我使用 jQuery 1.3+ 以来,除了一个定时测试之外的所有测试都在使用它。另一个是我在 2000 年发现的纯 JavaScript。我停止了这条路线,因为运行测试大约需要 150 秒。我已经阅读了很多与选择单个元素相关的 jQuery 优化网页。 '#id' 是使用它的最佳情况,但现在我遇到了在一个包含多个复选框列的相当大的表中检查一列中的所有复选框

我所做的是设置一个页面,该页面创建 20,000 个表行,其中包含两个复选框列。目标是检查第二列,看看花了多长时间,然后取消选中它们,看看花了多长时间。显然我们想要最短的时间。我只使用 IE6 和 7,就我而言,我的所有用户都会这样做。

你说 20,000 行?我也是这么说的,但这将要投入生产(不在我的手中),现在改变已经太晚了。我只是想在时钟还剩 1 秒时向玛丽致敬。此外,我了解到 input.chkbox 不是最快的选择器(对于 IE7)! :)

问题是,有没有更好的方法来做这个 jQuery 或其他方式?我希望它能够在不到半秒的时间内在我的机器上运行。

所以你不必重新输入我已经完成的所有废话这里是我想出的测试内容:

更新了 4 月 14 日上午,以包括进一步的计时赛:

<form id="form1" runat="server">
    <div>
        <a href="#" id="one">input[id^='chkbox'][type='checkbox']</a><br />
        <a href="#" id="two">#myTable tr[id^='row'] input[id^='chkbox'][type='checkbox']</a><br />
        <a href="#" id="three">#myTable tr.myRow input[id^='chkbox'][type='checkbox']</a><br />
        <a href="#" id="four">tr.myRow input[id^='chkbox'][type='checkbox']</a><br />
        <a href="#" id="five">input[id^='chkbox']</a><br />
        <a href="#" id="six">.chkbox</a><br />
        <a href="#" id="seven">input.chkbox</a><br />
        <a href="#" id="eight">#myTable input.chkbox</a><br />

        <a href="#" id="nine">"input.chkbox", "tr"</a><br />
        <a href="#" id="nine1">"input.chkbox", "tr.myRow"</a><br />
        <a href="#" id="nine2">"input.chkbox", "#form1"</a><br />
        <a href="#" id="nine3">"input.chkbox", "#myTable"</a><br />

        <a href="#" id="ten">input[name=chkbox]</a><br />
        <a href="#" id="ten1">"input[name=chkbox]", "tr.myRow"</a><br />
        <a href="#" id="ten2">"input[name=chkbox]", "#form1"</a><br />
        <a href="#" id="ten3">"input[name=chkbox]", "#myTable"</a><br />

        <a href="#" id="ten4">"input[name=chkbox]", $("#form1")</a><br />
        <a href="#" id="ten5">"input[name=chkbox]", $("#myTable")</a><br />

        <a href="#" id="eleven">input[name='chkbox']:checkbox</a><br />
        <a href="#" id="twelve">:checkbox</a><br />
        <a href="#" id="twelve1">input:checkbox</a><br />
        <a href="#" id="thirteen">input[type=checkbox]</a><br />

        <div>
            <input type="text" id="goBox" /> <button id="go">Go!</button>
            <div id="goBoxTook"></div>
        </div>

        <table id="myTable">
            <tr id="headerRow"><th>Row #</th><th>Checkboxes o' fun!</th><th>Don't check these!</th></tr>
            <% for(int i = 0; i < 20000;i++) { %>
            <tr id="row<%= i %>" class="myRow">
                <td><%= i %> Row</td>
                <td>
                    <input type="checkbox" id="chkbox<%= i %>" name="chkbox" class="chkbox" />
                </td>
                <td>
                    <input type="checkbox" id="otherBox<%= i %>" name="otherBox" class="otherBox" />
                </td>
            </tr>
            <% } %>
        </table>
    </div>

    <script type="text/javascript" src="<%= ResolveUrl(" ~/") %>Javascript/jquery.1.3.1.min.js"></script>
    <script type="text/javascript">

        $(function () {
            function run(selectorText, el) {
                var start = new Date();
                $(selectorText).attr("checked", true);
                var end = new Date();
                var timeElapsed = end - start;
                $(el).after("<br />Checking Took " + timeElapsed + "ms");

                start = new Date();
                $(selectorText).attr("checked", false);
                end = new Date();
                timeElapsed = end - start;
                $(el).after("<br />Unchecking Took " + timeElapsed + "ms");
            }

            function runWithContext(selectorText, context, el) {
                var start = new Date();
                $(selectorText, context).attr("checked", true);
                var end = new Date();
                var timeElapsed = end - start;
                $(el).after("<br />Checking Took " + timeElapsed + "ms");

                start = new Date();
                $(selectorText, context).attr("checked", false);
                end = new Date();
                timeElapsed = end - start;
                $(el).after("<br />Unchecking Took " + timeElapsed + "ms");
            }

            $("#one").click(function () {
                run("input[id^='chkbox'][type='checkbox']", this);
            });

            $("#two").click(function () {
                run("#myTable tr[id^='row'] input[id^='chkbox'][type='checkbox']", this);
            });

            $("#three").click(function () {
                run("#myTable tr.myRow input[id^='chkbox'][type='checkbox']", this);
            });

            $("#four").click(function () {
                run("tr.myRow input[id^='chkbox'][type='checkbox']", this);
            });

            $("#five").click(function () {
                run("input[id^='chkbox']", this);
            });

            $("#six").click(function () {
                run(".chkbox", this);
            });

            $("#seven").click(function () {
                run("input.chkbox", this);
            });

            $("#eight").click(function () {
                run("#myTable input.chkbox", this);
            });

            $("#nine").click(function () {
                runWithContext("input.chkbox", "tr", this);
            });


            $("#nine1").click(function () {
                runWithContext("input.chkbox", "tr.myRow", this);
            });
            $("#nine2").click(function () {
                runWithContext("input.chkbox", "#form1", this);
            });
            $("#nine3").click(function () {
                runWithContext("input.chkbox", "#myTable", this);
            });

            $("#ten").click(function () {
                run("input[name=chkbox]", this);
            });

            $("#ten1").click(function () {
                runWithContext("input[name=chkbox]", "tr.myRow", this);
            });

            $("#ten2").click(function () {
                runWithContext("input[name=chkbox]", "#form1", this);
            });

            $("#ten3").click(function () {
                runWithContext("input[name=chkbox]", "#myTable", this);
            });

            $("#ten4").click(function () {
                runWithContext("input[name=chkbox]", $("#form1"), this);
            });

            $("#ten5").click(function () {
                runWithContext("input[name=chkbox]", $("#myTable"), this);
            });

            $("#eleven").click(function () {
                run("input[name='chkbox']:checkbox", this);
            });

            $("#twelve").click(function () {
                run(":checkbox", this);
            });

            $("#twelve1").click(function () {
                run("input:checkbox", this);
            });

            $("#thirteen").click(function () {
                run("input[type=checkbox]", this);
            });

            $('#go').click(function () {
                run($('#goBox').val(), this);
            });
        });
    </script>
</form>

【问题讨论】:

  • 我的意思不是无益,但是一页中的 20k 行只是糟糕的设计。你应该解决这个问题。 :)
  • 嗯...不开玩笑。 :) 我没有这样做!现在没有足够的时间来为这个版本修复它。这将是下一个版本中要做的第一件事。到目前为止,这个项目带来了许多“有趣”的挑战。

标签: javascript jquery performance


【解决方案1】:

input[name=chkbox] 将成为我机器上 IE7 下最快的 jQuery 选择器。

Unchecking Took 2453ms
Checking Took 2438ms
Unchecking Took 2438ms
Checking Took 2437ms
Unchecking Took 2453ms
Checking Took 2438ms

input.chkbox 和...

Unchecking Took 2813ms
Checking Took 2797ms
Unchecking Took 2797ms
Checking Took 2797ms
Unchecking Took 2813ms
Checking Took 2797ms

input:checkbox.chkbox似乎绑定了

Unchecking Took 2797ms
Checking Took 2797ms
Unchecking Took 2813ms
Checking Took 2781ms

.chkbox 几乎是 input.chkbox 的两倍

Unchecking Took 4031ms
Checking Took 4062ms
Unchecking Took 4031ms
Checking Took 4062ms

javascript for 循环是迄今为止最糟糕的:

Checking Took 149797ms

150 秒!它也锁定了浏览器。这让我对 jQuery 印象深刻。老实说,我没想到它会这么慢。可能是因为我正在遍历每个单独的元素,然后它必须找到......

这对我来说也很有趣:

输入[id^='chkbox']

Unchecking Took 3031ms
Checking Took 3016ms

花费的时间少于

输入[id^='chkbox'][type='checkbox']

Unchecking Took 3375ms
Checking Took 3344ms

我想既然我发布了更多过滤器,它会更快。不!

为复选框指定更多路径会使其速度变慢:

#myTable tr[id^='row'] input[id^='chkbox'][type='checkbox']

Checking Took 10422ms

它甚至没有运行第二次取消选中,因为它询问我是否要继续在我的计算机上运行脚本。疯狂的! :P

4/14 早上更新:

有人提出设置上下文:我实际上做了其中的一些,这让我大吃一惊,与网上很多人所说的相反在 IE7 上这些速度较慢!以下是我指定的几个不同上下文与上面更快的选择器配对的时间:

"input.chkbox", "tr"

Checking Took 8546ms

“input.chkbox”、“tr.myRow”

Checking Took 8875ms

“input.chkbox”、“#form1”

Unchecking Took 3032ms
Checking Took 3000ms

“input.chkbox”、“#myTable”

Unchecking Took 2906ms
Checking Took 2875ms

当前获胜者(仍然):input[name=chkbox]

Unchecking Took 2469ms
Checking Took 2453ms

"input[name=chkbox]", "tr.myRow"

Checking Took 9547ms

"input[name=chkbox]", "#form1"

Unchecking Took 3140ms
Checking Took 3141ms

"input[name=chkbox]", "#myTable"

Unchecking Took 2985ms
Checking Took 2969ms

2014 年 4 月 2 日上午更新

在我注意到与http://beardscratchers.com/journal/jquery-its-all-about-context 的语法不同后,我想我可能会有更好的选择。似乎这些与 它们提供了稍微好一点的时间不同,但仍然没有击败非上下文选择器 - 该死。

"input[name=chkbox]", $("#form1")

Unchecking Took 3078ms
Checking Took 3000ms
Unchecking Took 3078ms
Checking Took 3016ms

"input[name=chkbox]", $("#myTable")

Unchecking Took 2938ms
Checking Took 2906ms
Unchecking Took 2938ms
Checking Took 2921ms

2014 年 4 月 3 日上午更新

Russ 想让我试试这些,他们取消/选择了所有的框,但这又很有趣:

:复选框

Unchecking Took 8328ms
Checking Took 6250ms

输入:复选框

Unchecking Took 5016ms
Checking Took 5000ms

-> 最快?!?! 输入[type=checkbox]

Unchecking Took 4969ms
Checking Took 4938ms

第三个最快的事实很有趣,因为这与我的想法相反。为什么(至少对于 IE7) :checkbox 不使用 type=checkbox 来获得更快的时间?这些分数非常接近,但检查时间减少了 62 毫秒。另外,为什么前两个完全不同?除了可以带复选框的输入之外,还有其他元素吗?

【讨论】:

  • 更多选择条件不会加快查询速度,除非每个条件都减小集合大小。由于所有复选框都在表格行中并且具有输入,因此将它们添加为条件没有帮助。
  • “我想既然我发布了更多过滤器,它会更快。”正如 Zan 所说,更多过滤器 = 更多检查 = 更多处理 = 更多时间。除非每个过滤器显着减少下一个过滤器的设置大小,否则它只会占用周期。
【解决方案2】:

我尚未对此进行测试,但您可以尝试在页面加载时构建一个复选框引用的数组 [],然后在每次要进行更改时简单地对其进行迭代?

您会为页面加载付出性能成本,但它可能比每次遍历 DOM 更快。嘿,至少您会在用户“停机时间”中执行繁重的工作(人们需要多长时间才能找到并单击取消选择/选择选项)。

【讨论】:

  • 或者我想知道您是否可以在第一次(或加载时)将它们“缓存”到一个数组中,然后再次点击它会更快。好主意,我试试看。
  • 会做,但可能是明天,因为工作日快结束了。
  • 我最大的问题是他们很可能永远不会点击全选。对于 20k 行,它实际上将浏览器锁定了 2 秒。我仍然会试一试,但这可能是个问题。
  • 如果您担心初始加载会锁定 UI 线程,您可以使用 window.setTimeout 将其推送到单独的线程中。
  • 我得看看怎么做。
【解决方案3】:

我唯一的建议可能也行不通。切换浏览器。但我只有一家公司真正同意这一点。我们让公司改用 FireFox,特定用户改用 Google Chrome。 IE 使用 JavaScript 太慢了。

另外,您可以尝试预先缓存 jquery 查询列表。

如果一切都失败了,用心理学来解决它。这意味着让用户知道某些事情需要很长时间。在函数执行时放置一个“请稍候”的 div。这样,用户就知道浏览器不仅被锁定,而且他们知道什么时候可以恢复工作。通过这样做,我已经“解决”了许多缓慢的页面。

【讨论】:

  • 大声笑,是的,只是不会发生。我很“幸运”能够使用 IE7。其他所有人都必须使用 IE6。我会研究预缓存。
  • 另一个选项...您正在使用 JQuery 属性操作来设置选中:$(selectorText).attr("checked", false);您也可以尝试 $(selectorText).each(function(){ this.checked = false });没有保证,但可能值得一试。
  • 想过这样做。我会试一试,看看会发生什么。我们实际上是在 150 秒之前发出请稍候的通知,但将其降低到 2-3 会很棒。
【解决方案4】:

您是否尝试过带有context 的jQuery 选择器,看看这是否能提高性能?大概这些控件将位于 ASP.NET 表单中,并且可能是另一个唯一可识别的元素?

例如,你在哪里

$("input[id^='chkbox']")

试试

$("input[id^='chkbox']", "#myFormID")

Here's a BeardScratchers article 上下文

编辑:

根据您的情况,根据您的情况,似乎 2.45-6 秒可能是您可以达到的最快速度。

为了完整起见,您是否尝试过以下选择器?

$(':checkbox')
$('input[type=checkbox]')

【讨论】:

  • 等等...阅读全文,看来我提供的上下文可能有误??
  • 仍然值得一试。似乎 2.45-6 秒可能是您可以达到的最快速度。
  • 在这一点上看起来像 :) 实际上比他们使用 javascript 方法之前更好。使用这两个选择器,它会选择所有复选框,而不仅仅是第二列。
  • 我想,什么干草,我也试试。再次非常有趣!
猜你喜欢
  • 2015-10-01
  • 2010-11-19
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
相关资源
最近更新 更多