jQuery:选择器特异性是否会提高 .on() 委托的性能?

jQuery: Does selector specificity increase performance with .on() delegation?

在使用 .on() 增加委托事件绑定的特异性时是否有性能提升?

如何测试这个?

例如,第二个语句是否比第一个语句更高效:

$('.foo').on('mouseenter', ':has(.other)', function (e) {
    console.log(e);
});

$('.bar').on('mouseenter', 'button:has(.other)', function (e) {
    console.log(e);
});

$('.foo').on('mouseenter', ':has(.other)', function (e) {
  console.log(e);
});

$('.bar').on('mouseenter', 'button:has(.other)', function (e) {
  console.log(e);
});
.foo, .bar {
  margin: 2em auto;
  text-align: center;
}
<div class="foo">
  <button type="button">Hello
    <span class="other">World</span>
  </button>
</div>

<div class="bar">
  <button type="button">Hello
    <span class="other">World</span>
  </button>
</div>

我主要担心的是,通过委派监听 mouseenter 事件会消耗性能,如果有一种方法可以测试此类事件处理程序的性能。

更新

我应该澄清一下,我并不是要了解一般使用委托对性能的影响。我希望了解在用户交互期间使用 mouseenter 的委托对性能的影响(因为用户的鼠标在绑定元素中同时输入委托和非委托元素),以及是否通过使用更多来提高性能委派的特定选择器。

我倾向于假设没有,因为在根据委托选择器检查之前,每个事件都必须冒泡到绑定元素。

但是有没有办法对此进行测试?

具体有帮助……一点点。

根据 this JSPerf test,在已发布的示例中向选择器添加特定性会持续提高重复测试的性能,但可以想象,在用户交互级别,事件在相对较小的范围内偶尔发生,收益可以忽略不计迭代。

在一些测试中,差异足够小并且在误差范围内,可以被认为是统计等效的。

处理程序中的选择器过滤有问题

但最令人惊讶的结果是上面一位评论者建议的辅助第三次测试,该测试从选择器中取出 :has() 并用回调函数中的 .has() 检查替换它,它始终比在选择器中使用 :has() 执行得慢 — 通常每秒执行 100 次或更多操作。

考虑到 jQuery documentation for :has() 表明您应该期待更好的性能,这可以说是不容忽视的,尤其值得注意:

Because :has() is a jQuery extension and not part of the CSS specification, queries using :has() cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. For better performance in modern browsers, use $( "your-pure-css-selector" ).has( selector/DOMElement ) instead.

我不怀疑在 .has() 仅用于减少匹配元素集的选择器语句中,人们可以获得更好的性能;但我怀疑测试中显示的性能消耗是通过将 .has() 检查移动到事件数据正在传递的事件处理程序中打破该约定的结果,一个新的 jQuery 对象正在构造this,并且 .length 正在 if 语句中被访问和检查。


测试配方

为了制定测试,配置了三个事件绑定基准并应用于相同的 HTML 标记,然后是相同的事件触发测试用例——模拟用户将鼠标悬停在各种委托和非委托元素上屏幕 — 应用于三个基准中的每一个以进行比较。

基准1:

    $('.foo').on('mouseenter', ':has(.other)', function(e) {
      console.log(e);
    });

基准2:

    $('.foo').on('mouseenter', 'button:has(.other)', function(e) {
      console.log(e);
    });

基准3:

    $('.foo').on('mouseenter', 'button', function(e) {
      if ($(this).has('.other').length) {
        console.log(e);
      }
    });

HTML:

<div class="foo">
    <button type="button" id="A">some text</button>
    <button type="button" id="B"><span class="other">some text</span></button>
    <div id="C">some text</div>
</div>

测试用例:

$('#A').trigger('mouseenter');
$('#B').trigger('mouseenter');
$('#C').trigger('mouseenter');