【问题标题】:Efficiency: one event handler or multiple效率:一个事件处理程序或多个
【发布时间】:2015-03-30 10:02:30
【问题描述】:

有一个关于将多个对象绑定到单击事件here 的问题有一个很好的答案,但答案只涉及容器内的按钮。我想知道如果有一个更复杂的结构会发生什么,其中按钮内有元素,容器内有非按钮元素。使用单个事件处理程序是否仍然更有效?

考虑一下这个(不那么复杂的)HTML:

<div id="container">
    <div class="some nice red block"></div>
        <div id="button_1" class="button">
           <span>some text</span>
           <img src="button_1_img.jpg">
        </div>
    <p>some more text</p>
    <img src="a_nice_pic.png">
        <div id="button_2" class="button">
           <span>some text</span>
           <img src="button_2_img.jpg">
        </div>
        <div id="button_3" class="button">
           <span>some text</span>
           <img src="button_3_img.jpg">
           <div class="some icon"></div>
        </div>
    <p>some more text</p>
    <img src="a_nice_pic.png">

    //... more text, images and let's say up to 20 buttons

</div>

我可以:

  1. 为所有按钮分别添加事件监听器
  2. 只向容器添加一个事件处理程序

万一我需要:

document.getElementById('button_1').addEventListener('click',dosomething,false);
document.getElementById('button_2').addEventListener('click',dosomething,false);
//etc... 18x

function dosomething(e){
   var button=e.currentTarget.id;
   //do something based on button id;
   }

然后,我将 20 个点击处理程序附加到 20 个不同的按钮上,这些按钮只有在单击按钮时才会触发。

如果我需要案例 2:

document.getElementById('container').addEventListener('click',dosomething,false);

function dosomething(e){
    var container=e.currentTarget;
    var clicked=e.target;

    while(clicked != container){
        if(clicked.className == 'button'){
            var button=clicked.id;
            //do something based on button id;
           return; 
           }
        else{
           clicked=clicked.parentNode;
           }
     }
}

现在我只有一个事件监听器。但它不仅会触发按钮,还会触发您在容器内单击的所有内容。它每次都必须向上移动 DOM 以检测单击的元素周围是否有按钮。

那么两者中哪一个在内存使用和性能方面最有效? 一个有更多事件处理程序但要做的事情更少,还是只有一个事件处理程序但代码更复杂?

我创建了一个fiddle 来展示差异。

[edit] 也许我把这个例子过于简单化了。有时会在最多 4 个容器中附加大约 200 多个均匀监听器。

【问题讨论】:

  • 你是否也在使用 jQuery?
  • 我宁愿为所有按钮设置一个通用类(您已经这样做了)并将点击事件绑定到这些按钮,然后捕获点击的目标。
  • @Cerberus。我没有使用 jQuery。

标签: javascript performance eventhandler


【解决方案1】:

有一个关于将多个对象绑定到单击事件here 的问题有一个很好的答案,但答案只涉及容器内的按钮。

没有。只有它的标记示例不包含其他元素,但它也适用于您的情况。

$(common parent selector).on('click', selector of target objects, function() {});
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^

您的标记将是 $("#container").on("click", ".button", …)

那么两者中哪一个在内存使用和性能方面最有效?一个有更多事件处理程序但要做的事情更少,还是只有一个事件处理程序但代码更复杂?

两者都没有。正如您刚刚注意到的,这是一种权衡:单个事件处理程序将占用更少的内存;并且多个事件处理程序在被点击时要做的事情更少。

我认为您的 20 个按钮没有任何问题。如果您使用数百个处理程序,内存需求只会影响性能。我建议使用更简单的解决方案——特别是如果你不使用为你做复杂事情的库——并且只有在性能下降时才尝试事件委托。不要过早地进行优化。

【讨论】:

  • 感谢您的回答。也许我不应该把这个例子过分简化,因为真正的 HTML 结构远比这复杂得多,而且有更多的按钮。您引用的解决方案是 jQuery,我没有使用它。但我觉得不知何故(如果我错了,请纠正我)jQuery 必须做同样的事情:要么搜索 DOM 并将事件绑定到所有找到的按钮,要么将一个事件绑定到容器并从 event.target 向上传播 DOM。恕我直言,它并没有过早地进行优化,而是选择两者中最好的并坚持下去,而不是以后不得不更改大量代码。
  • 是的,jQuery 也必须这样做。但是不,你不应该坚持一种模式。使用适当的辅助函数,无需更改大量代码即可轻松切换(在 jQuery 中,这将是 $(container, targets, handler)$(container + targets, handler) - 差别很小)。
【解决方案2】:

正如我在评论中所说,我会按照以下方式进行操作。

var buttons = document.querySelectorAll('.button');
[].forEach.call(buttons, function(button) {
  button.addEventListener("click", dosomething);
});

function dosomething(e) {
    var button=e.currentTarget.id;
    alert (button);
}

这只会将事件侦听器附加到按钮,而不是像您在问题中显示的容器。 atm 有点过时,但会回来添加更多细节 :) 同时,大家:随时编辑和添加您宝贵的 cmets!

【讨论】:

  • 感谢您的回答。也许我应该更清楚。我的问题不是关于如何添加事件处理程序,而是关于我应该添加多少:一个用于容器还是每个按钮一个?
  • 当然。 Bergi 涵盖了您在性能/优化方面的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多