在使用.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
委派的性能影响(因为用户的鼠标在绑定元素中输入委托和非委托元素),并且如果通过使用更多元素获得性能提升特定的委托选择器。
我倾向于假设没有,因为在对照委托选择器进行检查之前,每个事件都必须冒泡到绑定元素。
但有没有办法测试呢?
答案 0 :(得分: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()
检查移动到事件数据传递的事件处理程序来打破该约定的结果,从{{1}构造新的jQuery对象},this
正在.length
语句中访问和检查。
为了制定测试,配置了三个事件绑定基准并应用于相同的HTML标记,然后应用相同的事件触发测试用例 - 模拟用户将鼠标悬停在屏幕上的各种委托和非委托元素上 - 用于比较的三个基准中的每一个。
基准1:
if
基准2:
$('.foo').on('mouseenter', ':has(.other)', function(e) {
console.log(e);
});
基准3:
$('.foo').on('mouseenter', 'button:has(.other)', function(e) {
console.log(e);
});
<强> HTML:强>
$('.foo').on('mouseenter', 'button', function(e) {
if ($(this).has('.other').length) {
console.log(e);
}
});
测试案例
<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>