在性能方面遇到困难时,我该如何将其更改为用于循环

Struggling with performance how do I change this to use for loops?

本文关键字:循环 用于 遇到 方面 性能      更新时间:2023-09-26

我有一个函数,用于检查edit-error类表每行中的每个单元格。如果在特定行的任何单元格中都发现了这种情况(单元格值尚未通过验证),那么我将从整行中删除edit-submit类,并取消选中该行第一个td中的复选框。

当有大量行(1000+)时,我会在性能上遇到困难,所以我想我可以尝试循环,但我不是JavaScript专家,所以我正在寻求帮助。

原始代码如下:

var checkErrors = function () {
    $('#results tr:not(:first)').each(function () {
        $('td:first input:checkbox', $(this)).attr('checked', 'checked');
        $(this).addClass('edit-submit');
        $(this).find('td').each(function () {
            if ($(this).hasClass('edit-error')) {
                $('td:first input:checkbox', $(this).parent('tr')).removeAttr('checked');
                $(this).parent().removeClass('edit-submit');
            }
        });
    });
}

该表的id为#results。我首先要做的是检查所有复选框,并将edit-submit类添加到每一行,然后循环检查所有单元格中的错误。

我正在寻求任何有关此功能性能改进的帮助。

编辑

添加表html是有意义的。对此深表歉意:

<table id="results">
    <tbody>
        <tr>
            <th>&nbsp;</th>
            <th>Policy Number</th>
            <th>Quota Code</th>
            <th>Contract Date</th>
        </tr>
        <tr>
            <td><input type="checkbox"></td>
            <td class="edit-error">ABC123%</td>
            <td>123</td>
            <td class="edit-error">99/99/9999</td>
        </tr>
        <tr class="edit-submit">
            <td><input type="checkbox" checked="checked"></td>
            <td>ABC123</td>
            <td>123</td>
            <td>16/03/2012</td>
        </tr>
    </tbody>
</table>

这将显示在页面上:

--------------------------------------------------||保单号|额度编码|合同日期|--------------------------------------------------||ABC123%|123 |99/99/9999|--------------------------------------------------|X | ABC123 | 123 | 2012年3月16日|--------------------------------------------------

有几种方法可以在不使用普通JS for循环的情况下加快代码的速度。仅举几个例子:

  • 您已经在外部.each()循环中引用了当前行,因此请使用它,而不是在内部循环中调用$(this).parent()
  • 如果只想处理具有特定类的td元素,可以在选择器中包含该类,而不是调用.hasClass()
  • 通过存储对返回的jQuery对象的引用和/或通过链接,避免多次调用同一选择器
  • 当提供上下文作为$()的第二个参数时,您可以直接传递DOM元素或this,而无需将其封装在另一个$()调用中
  • 如果你知道总是有一个复选框,你可以直接取消选中它来保存函数调用

因此:

var checkErrors = function () {
    $('#results tr:not(:first)').each(function () {
        var $tr = $(this),
            cb = $('td:first input:checkbox', this)[0];
        cb.checked = true;
        $tr.addClass('edit-submit')
           .find('td.edit-error').each(function () {
                cb.checked = false;
                $tr.removeClass('edit-submit');
           });
    });
};

然而,根本不需要tds上的内部循环,因为您只需要测试错误类所在的行中是否有tds,而不需要实际循环所有tds。此外,为了更好地衡量,这里有一种使用for循环而不是.each()的方法-请注意,如果您只选择所有行,然后从第二行开始循环,则可以避免复杂的非第一选择器:

var checkErrors = function () {
    var $rows = $('#results tr'),
        i;
    for (i = 1; i < $rows.length; i++) {
        var $tr = $rows.eq(i),
            cb = $tr.find('td:first input:checkbox')[0];
        if ($tr.find('td.edit-error').length === 0) {
           cb.checked = true;
           $tr.addClass('edit-submit');
        } else {
           cb.checked = false;
           $tr.removeClass('edit-submit');
        };
    }
};

尝试为$(this)设置一个变量。您还需要使用find('td')吗?$('td',this)会做同样的事情但更有效吗?

试试这个:

   $.each($('#results .edit-error').parent(),function(){
            $(this).removeClass('edit-submit').find('td:first-child input:checkbox').removeAttr('checked');
});

为$(this)使用一个变量。

您的选择器也可以改进:使用$('#that').find('#this') 而不是$('#this', '#that')

以下是经过这些优化的改进版本。

var checkErrorsOptimized = function () {
    $('#results tr:not(:first)').each(function () {
        var $this = $(this);       
        $this.find('td:first input:checkbox').attr('checked', 'checked');
        $this.addClass('edit-submit');
        $this.find('td').each(function () {
            var $that = $(this);
            if ($that.hasClass('edit-error')) {
                $that.parent('tr').find('td:first input:checkbox').removeAttr('checked');
                $that.parent().removeClass('edit-submit');
            }
        });
    });
}

你可以在这个jsFiddle上看到它(使用Firebug评测):http://jsfiddle.net/5kBsU/3/