【问题标题】:Optimizing javascript performance with many event listeners使用许多事件侦听器优化 javascript 性能
【发布时间】:2015-03-12 07:40:44
【问题描述】:

我目前正在构建一个允许搜索元素的网站,并将结果添加到一个大表中(想想数百个结果)。结果表中的每个元素都可以通过多种方式进行操作(自定义 javascript 0-5 星评级、切换折叠面板以获取其他选项等)。

如果我在我的 android 平板电脑上使用该网站,javascript 部分的性能非常缓慢,所以我想知道如何提高性能。

我考虑过的一个选项是,除了单个 mouse-enter 事件之外,不在结果行上绑定任何事件侦听器,然后仅当鼠标悬停在给定元素上时才绑定实际事件侦听器。

任何其他提高性能的想法将不胜感激。

我的大部分 javascript 代码都是基于 jquery 的,所以如果您有任何 jquery 特定的优化,我也将不胜感激。

【问题讨论】:

  • 使用.on() 方法在当前或未来元素上绑定事件不应降低性能,因为在您的元素成为此类事件的发起者之前没有事件。什么是呆滞?切换?
  • 尝试使用 css 选择器以获得更好的性能。此外,当您使用 jquery 时,您应该知道 jsperf 以检查哪些选择器更适合使用。
  • @Jai “尝试使用 css 选择器以获得更好的性能”你能解释一下吗?
  • 考虑对那些“数百个结果”进行分页。并且没有提高性能的神奇秘诀。涉及的因素很多。
  • @RokoC.Buljan 正如 OP 提到的关于 jquery 的那样,所以 OP 可能使用了一些 jquery 提供的自定义选择器,例如 :last, [id^="someid"] 等,我猜可能在那里。

标签: javascript jquery performance optimization event-listener


【解决方案1】:

您可以研究一下 javaScript 事件委托。 SO上有很多答案(例如here)和很多好文章(herehere)。

基本上,您的想法实际上是一个很好的解决方案。因此,不是将一百行与它们自己的事件处理程序绑定,而是只绑定它们的共同父项,当它的任何子项接收到鼠标输入时,它将触发一个事件。

粗略地说,而不是这个:

$('tr').on("click", function() {});

你会这样做:

$('table').on('click', 'tr', function() {});

这显然是一个非常简化的示例,但它应该足以构建一个好的模式。

作为旁注,检查被触发的事件是一件非常有趣的事情(嗯,至少对我来说......):

$('table').on('click', 'tr', function(evt) {
   console.log(evt);
});

并查看一个事件携带了多少信息,以及通过简单的单击或鼠标输入即可获得多少有用的信息。

VanillaJs

当然,不用任何库也能达到同样的效果。

可以从答案开头链接的 David Walsh 的文章中获取使用 Vanilla JS 的简单实现,大致如下:

// Get the element, add a click listener...
document.getElementById("#myTable").addEventListener("click", function(e) {
    // e.target is the clicked element.
    // Check if it was a <tr>...
    if(e.target && e.target.nodeName == "TR") {
        // Element has been found, do something with it
    }
});

如果您尝试此代码,尽管实际的 target.element 很可能是 &lt;td&gt;,而不是我们想要的 &lt;tr&gt;。 这意味着我们必须更聪明一点,向上遍历 DOM 以查看点击的元素 (&lt;td&gt;) 是否包含在我们真正想要的元素 (&lt;tr&gt;) 中。

帮助您入门的粗略实现如下所示:

function walk(startEl, stopEl, targetNodeName) {
  if (!startEl || startEl === stopEl || startEl.nodeName === 'BODY') {
    return false;
  }

  if (startEl.nodeName === targetNodeName) {
    // Found it, return the element
    return startEl;
  }

  // Keep on looking...
  return walk(startEl.parentNode, stopEl, targetNodeName);
}

const container = document.getElementById('myTable');

container.addEventListener('click', (e) => {
  const clickedElm = walk(e.target, container, 'TR');
  console.log(clickedElm);
  if (clickedElm) {
    clickedElm.classList.add('clicked');
  }
})

查看fiddle 或下面的 sn-p:

function walk(startEl, stopEl, targetNodeName) {
  if (!startEl || startEl === stopEl || startEl.nodeName === 'BODY') {
    return false;
  }

  if (startEl.nodeName === targetNodeName) {
    return startEl;
  }

  return walk(startEl.parentNode, stopEl, targetNodeName);
}

const elem = document.getElementById('myTable');

elem.addEventListener('click', (e) => {
  const clickedElm = walk(e.target, elem, 'TR');
  console.log(clickedElm);
  if (clickedElm) {
    clickedElm.classList.add('clicked');
  }
})
table {
  width: 100%;
}
tr {
  background: #ddd;
}
.clicked {
  background: teal;
}
 <table id="myTable">
   <tr>
     <td>one</td>
   </tr>
   <tr>
     <td>two</td>
   </tr> 
   <tr>
     <td>three</td>
   </tr> 
   <tr>
     <td>four</td>
   </tr> 
   <tr>
     <td>five</td>
   </tr> 
   <tr>
     <td>six</td>
   </tr>    
 </table>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 2014-06-18
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 2020-12-23
    • 1970-01-01
    相关资源
    最近更新 更多