【问题标题】:When should one event listener be used and when should multiple ones be used?什么时候应该使用一个事件监听器,什么时候应该使用多个事件监听器?
【发布时间】:2014-12-30 00:12:23
【问题描述】:

在这种情况下,当使用事件侦听器(为此使用 jQuery)时,我对性能方面的最佳选择是什么感到困惑。

案例 1: 假设您有一个包含两个输入的 div,并且您想为 keyUp 事件“监听”这两个输入。 (这个div是文档中唯一的东西,它的高度和宽度也是整个文档的高度和宽度)

        <div id=formContainer>
            <input type="text" id="a">
            <input type="text" id="b">
        </div>

什么会更好? : 将“委托事件侦听器”附加到 formContainer 或将事件侦听器附加到每个输入

案例 2: 现在,假设你有一个像这样的 html 结构(同样,chatContainer 是文档的全高和全宽,它和它的子级是唯一的东西)

   <div id=chatContainer>

     <div id="menu"></div> //Has to listen to clicks for interactivity
     <div id="messagesWindow"></div> //Has to listen to clicks on every message appended
     <input type="text" id="inputSomething"> //Has to listen to keyUp events

   </div>

在这种情况下,最好将事件侦听器附加到每个 div/输入,还是将所有需要的事件侦听器附加到 chatContainer (keyUp, click)

我已经阅读了委托事件,但我不知道我是否正确。我只想做更好的事情,即使性能差异很小。 非常感谢。

【问题讨论】:

  • 直接添加事件 - 附加事件时会影响性能。委托事件 - 性能命中是事件被触发的时间。哪个更好用取决于实际的代码。
  • 在如此小的上下文中,任何一个都可以接受。如果您在触发keyUp 时触发事件使用相同的函数,则在创建时将它们附加到父div 没有问题。性能问题只会在您有很多 (1000 >)、进行大量 DOM 修改(此时出现垃圾收集问题)或当您有一个与事件相关的非常大的内存消耗函数时才会蔓延到您的应用程序中。
  • 另外,github.com/stevekwan/best-practices/blob/master/javascript/… 是 Javascript 和优化入门的好书。我强烈推荐它。
  • 读得很好,谢谢,我意识到当它变得更复杂时,上下文更重要,从这个意义上说,它似乎很清楚,但否则答案对我来说不是很直观。 Epascarello,好吧,那么,一次附加多个事件而不是一个事件所需的内存呢?我认为事件监听可能是存储在 RAM 中并且可能会变得很重的东西,或者这是一个完全错误的观点?当它被触发时,它会消耗 CPU 功率,但“监听”肯定存储在 RAM 中吗?

标签: javascript jquery html events


【解决方案1】:

我也不知道哪个更快(即使差异很小)。所以我写了测试代码

coffeescript 编写的代码

尽管您可以在 jsfiddle 上看到 javascript 代码,但它们是编译后的代码。

案例1 http://jsfiddle.net/5mnroam3/

(你的问题案例)

<div id=formContainer>
    <input type="text" id="a">
    <input type="text" id="b">
</div>

counterA = counterB = 0
$("#formContainer").click( (e) ->
  switch $(e.target).attr("id")
    when "a"
      counterA++
    when "b"
      counterB++
)
startTime = new Date()
for i in [0...10000]
  $("#a").trigger("click")
  $("#b").trigger("click")
endTime = new Date() - startTime
console.log("listen to container : #{endTime} ms","counterA is #{counterA}","counterB is #{counterB}")

counterA = counterB = 0
$("#formContainer").off("click")
$("#a").click((e) ->
  counterA++
)
$("#b").click((e) ->
  counterB++
)
startTime = new Date()
for i in [0...10000]
  $("#a").trigger("click")
  $("#b").trigger("click")
endTime = new Date() - startTime
console.log("listen to each elem : #{endTime} ms","counterA is #{counterA}","counterB is #{counterB}")

上面的代码在每次事件发生时都执行 10000 次点击“#a”和“#b”并执行“counter++”。 在我的macbook(MBP2013mid chrome最新)中,结果是

listen to container : 2224 ms counterA is 10000 counterB is 10000

listen to each elem : 1952 ms counterA is 10000 counterB is 10000

听每个元素会快一点。

案例2 http://jsfiddle.net/fbjyp5yL/

(案例目标元素有一个子元素,这意味着当你监听外部元素时,你必须检查被点击的元素是否有目标元素作为它的父元素,因为在事件回调函数中e.targetthis始终是您可以点击的最内部元素)

<div id="outer">
  <div id="element1">
    <div class="children1"></div>
    <div class="children2"></div>
  </div>
  <div id="element2">
    <div class="children1"></div>
    <div class="children2"></div>
  </div>
</div>

counterA = counterB = 0

$("#outer").click( (e) ->
  if $(e.target).closest("#element1").length
    counterA++
  else if $(e.target).closest("#element2").length
    counterB++
  else
    console.log("unexpected event")
)
startTime = new Date()
for i in [0...5000]
  $("#element1 .children1").trigger("click")
  $("#element1 .children2").trigger("click")
  $("#element2 .children1").trigger("click")
  $("#element2 .children2").trigger("click")
endTime = new Date() - startTime
console.log("listen to outer : #{endTime} ms",counterA,counterB)

$("#outer").off("click")
counterA = counterB = 0
$("#element1 .children1,#element1 .children2").click( (e) ->
  counterA++
)
$("#element2 .children1,#element2 .children2").click( (e) ->
  counterB++
)
startTime = new Date()
for i in [0...5000]
  $("#element1 .children1").trigger("click")
  $("#element1 .children2").trigger("click")
  $("#element2 .children1").trigger("click")
  $("#element2 .children2").trigger("click")
endTime = new Date() - startTime
console.log("listen to each elem : #{endTime} ms",counterA,counterB)

在这种情况下,我的结果是

listen to outer : 2547 ms 10000 10000

listen to each elem : 2159 ms 10000 10000

所以监听外部元素就像 case 1 一样慢,并且差异比 case1 大,即使通过 20000 次点击只有 300-400 毫秒。

结论

虽然使用外部元素或每个内部元素之间的差异很小,但在每个 div/输入上侦听事件会更快。我确定是否有 10 或 20 个内部元素,差异仍然足够小。所以选择随心所欲。

【讨论】:

  • 酷测试,我还从你的代码中学到了一些新东西。我想这在某种程度上衡量了每种方法的 CPU 响应,但每种方法消耗的内存量也很重要,不是吗?有没有办法用这样的测试来衡量这样的事情? (再一次,我不知道我是否正确地得到了这个内存/cpu 的东西!)。非常感谢您,我不妨选择这个作为答案,因为您付出了努力,这证明了一点。
猜你喜欢
  • 1970-01-01
  • 2016-05-09
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-12
相关资源
最近更新 更多