Javascript 加速选择器和方法

Javascript 加速选择器和方法,javascript,jquery,performance,css-selectors,Javascript,Jquery,Performance,Css Selectors,在深入研究jQuery/Sizzle源代码之前,我想在这里询问一下如何加快下面的方法 这是一个标准的“全选”复选框方案。标题单元格()有一个复选框,选中该复选框时,将选中其表的tbody中位于同一列中的所有其他复选框 这项工作: // We want to check/uncheck all columns in a table when the "select all" // header checkbox is changed (even if the table/rows/checkbox

在深入研究jQuery/Sizzle源代码之前,我想在这里询问一下如何加快下面的方法

这是一个标准的“全选”复选框方案。标题单元格(
)有一个复选框,选中该复选框时,将选中其表的
tbody
中位于同一列中的所有其他复选框

这项工作:

// We want to check/uncheck all columns in a table when the "select all"
// header checkbox is changed (even if the table/rows/checkboxes were 
// added after page load).
(function () {
    // use this dummy div so we can reattach our table later.
    var dummy = $("<div style=display:none />");

    // hook it all up!
    body.delegate(".js_checkAll", "change", function () {

        // cache selectors as much as possible...
        var self = $(this),
            // use closest() instead of parent() because 
            // the checkbox may be in a containing element(s)
            cell = self.closest("th"),
            // Use "cell" here to make the "closest()" call 1 iteration 
            // shorter. I wonder if "parent().parent()" would be faster 
            // (and still safe for use if "thead" is omitted)?
            table = cell.closest("table"),
            isChecked,
            index;

        // detaching speeds up the checkbox loop below.
        // we have to insert the "dummy" div so we know
        // where to put the table back after the loop.
        table.before(dummy).detach();

        index = cell.index();
        isChecked = this.checked;

        // I'm sure this chain is slow as molasses
        table
            // get only _this_ table's tbody
            .children("tbody")
            // get _this_ table's trs
            .children()
            // get _this_ table's checkboxes in the specified column
            .children(":eq(" + index + ") :checkbox")
            // finally...
            .each(function () {
                this.checked = isChecked;
            });

        // put the table back and detach the dummy for
        // later use
        dummy.before(table).detach();

    });
} ());
//当“全选”时,我们希望选中/取消选中表中的所有列
//标题复选框已更改(即使表格/行/复选框已更改)
//页面加载后添加)。
(功能(){
//使用这个虚拟div,以便稍后可以重新连接表。
虚拟变量=$(“”);
//把它都挂起来!
body.delegate(“.js_checkAll”,“change”,函数(){
//尽可能多地缓存选择器。。。
var self=$(此),
//使用最近的()而不是父级(),因为
//复选框可能位于包含元素中
单元格=自最近(“th”),
//在这里使用“cell”进行“最近的()”调用1次迭代
//更短。我想知道“parent().parent()”是否会更快
//(如果省略了“thead”,则仍可安全使用)?
表=最近的单元格(“表”),
我被检查过,
指数
//分离会加速下面的复选框循环。
//我们必须插入“dummy”div才能知道
//循环结束后,将桌子放回何处。
表.before(dummy).detach();
index=cell.index();
isChecked=此项已检查;
//我敢肯定这条链条很慢
桌子
//只拿这张桌子的主体
.儿童(“tbody”)
//获取此表的trs
.儿童()
//在指定列中获取此表的复选框
.children(“:eq(“+索引+”):复选框”)
//最后。。。
.每个(功能){
this.checked=isChecked;
});
//将桌子放回原位,分离假人,以便
//以后使用
dummy.before(table.detach();
});
} ());
然而,对于250多行,它开始变慢(至少在我的机器上)。用户可能需要最多500行数据,因此分页数据不是解决方案(项目已分页为500/页)


有没有办法再加速一点呢?

我不会像那样调用
.children()
。您最好只使用
.find()
查找复选框,然后检查父项:

table.find('input:checkbox').each(function(_, cb) {
  var $cb = $(cb);
  if ($cb.parent().index() === index) cb.checked = isChecked;
});
通过像使用标记名(“输入”)那样调用
.find()
,Sizzle将只使用本机
getElementsByTagName
(如果不是
querySelectorAll
)来获取输入,然后过滤复选框中的输入。我真的怀疑那会更快

如果查找父级索引的成本很高,您可以随时对其进行预计算,并将其存储在父级上的
.data()
元素中(或在复选框上)

否。如果省略
,则在HTML中会自动添加
元素,因为在HTML4中,开始标记和结束标记都是“可选”的。因此,在HTML中,它应该是
parent().parent().parent()
,但在XHTML中,它作为XML使用,没有可选标记,它应该是
parent().parent()

最好还是坚持使用
closest()
。更清楚的是,它不是特别慢,而且你只使用了一次,所以它并不重要

index = cell.index();
尽管同样,每个表只有一次索引,所以这并不重要,但是有一个标准的DOM属性可以直接获取表单元格的索引,这比要求jQuery搜索和计数以前的同级要快:
index=cell[0]。cellIndex

// we have to insert the "dummy" div so we know
// where to put the table back after the loop.
这有点难看。标准DOM对此有一个更好的答案:记住元素的
parentNode
nextSibling
(如果这是最后一个同级,则可能是
null
),完成后可以
parent.insertBefore(表,同级)

你应该考虑使用<代码>子()、EQ(index)< /代码>,而不是将其隐藏在选择器中。不会有太大的区别,但更清楚一点

在任何情况下,都可以通过使用更标准的DOM遍历表来节省jQuery的选择器引擎的大量工作:

$.each(table[0].tBodies[0].rows, function() {
    $(this.cells[index]).find('input[type=checkbox]').each(function() {
        this.checked = isChecked;
    });
});
选择器查询可以很快,当它们对文档进行操作并且只使用标准CSS选择器时。在这种情况下,jQuery可以将工作传递到浏览器的fast
document.querySelectorAll
方法。但是范围选择器(
find
$()
的第二个参数)无法优化,因为jQuery和选择器API之间对它们的含义存在分歧,像
:eq
:checkbox
这样的非标准Sizzle选择器将被拒绝。因此:

$('#tableid>tbody>tr>td:nth-child('+(index+1)+') input[type=checkbox]')

在使用
querySelectorAll
的现代浏览器上,速度可能会更快

也许您可以为所有复选框指定一个类,或者您可以尝试停止使用jQuery,因为在某些情况下它可能比自定义代码慢。我将尝试删除一些jQuery选择器。您可以使用JS模板引擎进行大列表操作,它比没有querySelectorAll的DOMEven更快,只需通过
getElementsByTagName
快速获取表中的所有
输入
元素就可以了,不会吧?会的,但我不知道OP是否希望这样。从获取列索引和避免嵌套表所做的努力来看,我猜可能还有其他输入/复选框/表在其中的某个地方,其内容需要避免。如果没有,那么是的,
$(表[0].tBodies[0])。使用
getElementsByTagName
查找('input')
)确实是最快的。对-如果确实有很多列复选框,那么最好的做法是在页面生成时用类标记复选框,或者,
$.each(table[0].tBodies[0].rows, function() {
    $(this.cells[index]).find('input[type=checkbox]').each(function() {
        this.checked = isChecked;
    });
});
$('#tableid>tbody>tr>td:nth-child('+(index+1)+') input[type=checkbox]')