发布于: 性能

优化选择器

选择器优化已不再像以前那样重要,因为越来越多的浏览器实现了 document.querySelectorAll(),选择元素的负担也从 jQuery 转移到了浏览器。然而,当选择器性能成为瓶颈时,仍有一些技巧值得铭记。

link jQuery 扩展

尽可能避免使用包含 jQuery 扩展 的选择器。这些扩展无法利用原生 querySelectorAll() DOM 方法带来的性能提升,因此需要使用 jQuery 提供的 Sizzle 选择器引擎。

1
2
3
4
5
// Slower (the zero-based :even selector is a jQuery extension)
$( "#my-table tr:even" );
// Better, though not exactly equivalent
$( "#my-table tr:nth-child(odd)" );

请记住,许多 jQuery 扩展(包括上述示例中的 :even)在 CSS 规范中没有完全对应的等价物。在某些情况下,这些扩展带来的便利性可能会超过其性能成本。

link 尝试隔离选择器中的非标准部分

当你选择元素时,jQuery 会使用你的选择器调用 querySelectorAll。如果 querySelectorAll 抛出错误,jQuery 将转而使用其 Sizzle 引擎。因此,如果你使用了至少一个非标准伪类,如 :contains():has:even:submit 等,你将无法利用原生的 querySelectorAll

1
2
3
4
5
// A long selection with nonstandard pseudo-classes inside
$( "#global.ready .part .list li a:contains('qwerty'):first" );
// A long standard selection with a filter outside (faster)
$( "#global.ready .part .list li a").filter( ":contains('qwerty'):first" );

link 避免过度的特异性(权重)

1
2
3
4
$( ".data table.attendees td.gonzalez" );
// Better: Drop the middle if possible.
$( ".data td.gonzalez" );

“更扁平”的 DOM 也有助于提高选择器性能,因为选择器引擎在查找元素时需要遍历的层级更少。

link 减少对 querySelectorAll 的调用

querySelectorAll 已经非常快了,如果你想保持这种速度,请尝试尽可能少地调用它。

1
2
3
4
5
6
// If in your HTML there are 2 .container with 5 div in each,
// this line will call querySelectorAll 13 times (1 + 2 + 2*5).
$( ".container" ).children( "div" ).find( ".robotarm" );
// Against only 1 call with this:
$( ".container div .robotarm" );

link 针对旧版浏览器的建议

当需要支持 Internet Explorer 8 及以下版本的旧版浏览器时,请考虑以下建议:

link 特异性(权重)

在选择器的右侧保持具体,在左侧保持简略。

1
2
3
4
5
// Unoptimized:
$( "div.data .gonzalez" );
// Optimized:
$( ".data td.gonzalez" );

在最右侧的选择器上尽可能使用 tag.class,而在左侧仅使用标签名或仅使用 .class

link 避免使用通配符选择器

指定或暗示可以在任何地方找到匹配项的选择器可能会非常慢。

1
2
3
$( ":radio" ); // Implied universal selection.
$( "*:radio" ); // Same thing, explicit now.
$( "input:radio" ); // Much better.