使用JavaScript事件委派而不是jQuery是否有性能优势?

时间:2014-07-25 21:02:07

标签: javascript jquery performance

JavaScript

parent.addEventListener("click", function(e) {
  if (e.target === child) { code }
});

VS

的jQuery

$(parent).on("click", child, function() {});

3 个答案:

答案 0 :(得分:4)

边缘,jQuery的on方法可以为您提供额外的功能,例如在事件冒泡到根时运行选择器,因此事件来自您期望的元素;如果你不小心,那可能会有问题。引用documentation,在“活动效果”下

  

在文档树顶部附近附加许多委托事件处理程序会降低性能。每次事件发生时,jQuery必须将该类型的所有附加事件的所有选择器与从事件目标到文档顶部的路径中的每个元素进行比较。

另一方面,普通的javascript做了一些更简单的事情,只是引发在该元素下发生的任何事件,所以你必须非常具体。

话虽如此,在正常情况下,现代引擎的性能差异可以忽略不计,例如几百个事件处理程序。

然而,正如@Patrick所指出的那样,对于某些特殊情况,您需要跟踪和获取事件需要数千个元素,这可能是灾难性的;在这种情况下运行选择器,对于每个事件,将杀死您的性能。有时您会受益于使用特殊技术,例如只将一个事件处理程序附加到所述元素的容器中,并使用e.target找出实际导致事件的原因。

答案 1 :(得分:0)

根据这个jsperf for event triggering performance,看起来jquery明显慢于native和Backbone事件。骨干事件比jquery或导航事件快几个数量级。

答案 2 :(得分:0)

我建议您不要使用引述的jQuery“选择器语法”,因为它绝对不会执行应做的操作,并且关于该主题的jQuery文档很糟糕。

在这个答案中,我将讨论

  1. 您的JavaScript代码段的哪个jQuery变体实际上与之相等”
  2. 正确的jQuery变体的性能以及是否重要
  3. 为什么要避免jQuery的“委托/选择器语法”(以及命名法有何问题)

正确的jQuery变体

$(parent).on("click", function(e) {
  if (e.target === child) { code }
});

这几乎类似于JavaScript变体,并且实际上是相同的,只是使用jQuery附加了处理程序。如果我喜欢使用jQuery或想使用jQuery来提高可读性,则可以使用它。

性能

我展示的变体和等效的JavaScript实际上是相同的。是的,jQuery变体会变慢,但是我不能列举使用jQuery的决定是正确的,而两者的性能差异是相关的情况。——我看到太多的项目在错误的一端优化了速度,在CPU周期和源代码文本中都使用糟糕的算法和重复代码。

保留jQuery并在此处进行优化是错误的结局。

损坏的jQuery选择器/委托语法

要创建“委托”处理程序,您需要做两件事

  1. 冒泡的事件
  2. 位于DOM上方的元素上的处理程序,覆盖目标

因此,任何合适的“通常”与jQuery关联的事件处理程序都是一个委托处理程序,即使不使用.on()的委托语法/签名。-这使得此jQuery命名法非常不合适

“ jQuery选择器委托处理程序”中真正发生的事情如下所示。在内部框中单击以查看jQuery 如何将目标和处理程序元素之间所有匹配的元素乘以一个单一事件。我不知道这种机制的合理用例,即使这种意外和奇怪的行为并没有打击您,jQuery所做的额外工作仍然存在。

它要么无效,仅消耗CPU周期,要么创建错误。

let lastEvent;
function analyze(tag, event) {
  const oe = event.originalEvent;
  console.log(`${tag}: Event on ${event.target.id} is ${lastEvent === oe ? 'repeated' : 'new'}.`);
  lastEvent = oe;
}

body.addEventListener('click', event =>
  console.log('click', event.target.id));
$(body).on('click', analyze.bind(null, '$click'));
$(body).on('click', '.hit', analyze.bind(null, '$delegateClick'));
div {
  margin: 20px;
  border: solid black 2px;
}

#inner {
  height: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<body id=body>
  <div id=outer class=hit>
    <div id=middle class=hit>
      <div id=inner class=hit>
      </div>
    </div>
  </div>
</body>