【问题标题】:jQuery: Does selector specificity increase performance with .on() delegation?jQuery:选择器特异性是否会通过 .on() 委托提高性能?
【发布时间】:2015-04-13 20:31:19
【问题描述】:

在使用.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 委托对性能的影响(因为用户的鼠标在绑定元素中同时输入委托和非委托元素),以及是否通过使用更具体的选择器来提高性能用于委托。

我倾向于假设没有,因为每个事件都必须冒泡到绑定的元素,然后再根据委托选择器进行检查。

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

【问题讨论】:

  • 试过运行任何 jsperf 测试?
  • 如果有的话,我认为第二个版本的性能可以忽略不计。无论如何,它们都会冒泡到祖先,而第二个版本需要检查节点类型以及类的存在。
  • 我建议,一般来说,在closest 调用中使用:has(就像on 在幕后所做的那样)会有糟糕的 性能.我会在选择器中测试button,然后在回调中使用.has() 方法。
  • @gfullam 我确信委托是正确的选择。但是,我会尽力确保 :has selector 不在您的选择器字符串中。它是一个 jQuery 选择器,而不是原生浏览器,因此非常慢。您正在树中的每个元素上使用它。如果你再做一个测试,比如button,然后使用.has function 来测试那个元素,它会有更好的性能,因为它可以更好地使用浏览器的内置功能。
  • @gfullam 我意识到这一点。我的意思是你应该尝试将:has从选择器中取出并在事件回调中进行测试;它会有更好的表现。请参阅these two examples:它们在功能上是等效的,但第一个具有更好的性能。

标签: jquery performance delegation event-delegation


【解决方案1】:

特异性有助于……一点点。

根据this JSPerf test 的说法,在发布的示例中为选择器添加特异性始终可以提高重复测试中的性能,但可以想象,在相对较小的迭代中偶尔发生事件的用户交互级别上,收益可能被认为可以忽略不计。

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

处理程序中的选择器过滤很麻烦

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

考虑到jQuery documentation for :has() 表明您应该期望这里有更好的性能,这可以说是不那么可忽略的并且特别值得注意:

因为:has() 是一个 jQuery 扩展而不是 CSS 的一部分 规范,使用 :has() 的查询不能利用 原生 DOM 提供的性能提升 querySelectorAll() 方法。为了在现代浏览器中获得更好的性能,请改用$( "your-pure-css-selector" ).has( selector/DOMElement )

我不怀疑在 .has() 仅用于减少匹配元素集的选择器语句中,人们可以期待更好的性能;但我怀疑测试中展示的性能消耗是通过将.has()检查移动到正在传递事件数据的事件处理程序中打破该约定的结果,正在从this构造一个新的jQuery对象,并且@正在访问 987654335@,并在 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');

【讨论】:

    猜你喜欢
    • 2022-06-28
    • 2013-06-13
    • 2010-09-07
    • 2020-03-02
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多