jQuery绑定点击事件和<a>标签的onclick事件之间的性能差异

6

我正在开发一个Web应用程序,使用大量JavaScript来完成任务。我有相当多的标签,绑定了Jquery点击事件来执行一些工作,所以我的代码看起来像这样:

HTML代码:

 <a href="#" id="id1">some content here</a>
 <a href="#" id="id2">some content here</a>
 ....

Jquery 代码:

 $('#id1').click(function(){
     //do something here..
     return false;
 });

 $('#id2').click(function(){
     //do something else here..
     return false;
 });

使用这种方法时,当脚本运行时,jQuery必须查找选择器(id1、id2等)。
但是还有另一种方法可以避免查找选择器,具体如下:
<a href="requireJs.htm" onclick="f1();return false">some content here</a>
<a href="requireJs.htm" onclick="f2();return false">some content here</a>

和 js 代码:

 function f1(){
     //do something here..
 });

 function f2(){
     //do something else here..
 });

哪种方法在性能方面更好?谢谢帮助。
5个回答

6

真正的性能提升是通过仅使用一个附加到父元素的事件处理程序,并使用 event.target 捕获生成的子元素事件,因为在 JavaScript 中默认情况下事件会向外层父级冒泡。

将您的链接包装在一个 div 中。

<div id="parent">
 <a href="#" id="id1">some content here</a>
 <a href="#" id="id2">some content here</a>
</div>

仅附加一个事件监听器

$('#parent').click(function(event){
    // event.target is now the element who originated the event
    $(event.target).doSomething();
});

这是速度的大幅提升,尤其是在老旧浏览器(如IE)和当你开始有很多事件时。

点击此处查看示例


1
那我可以把所有内容都包在一个 <div id="content"> 中,然后在页面中只使用一个点击事件吗? - bingjie2680
默认情况下,JS中的事件会一直冒泡直到找到一个事件监听器。例如,我点击了一个深度嵌套的元素,事件将一直向上冒泡到body元素(甚至可能是html,不确定),因此您可以为所有内容仅附加一个事件侦听器到body上。但要注意,这种链式冒泡会随着引擎需要冒泡的元素越多而变得更慢。对于变量也是如此,始终使用var语句声明它们,否则脚本将在链中查找已经初始化为该名称的变量,如果找到,则使用该值! - Jose Faeti
谢谢解释,那我需要检查像envent.target==id1这样的东西,然后做一些事情,我理解得对吗? - bingjie2680
这里有一个问题。因为你绑定了父级,所以无法在子级上停止事件传播。就像这个jsfiddle演示的一样...http://jsfiddle.net/xZAGr/11/ - kasdega
当然,因为事件已经传播,但是停止传播有什么意义呢?你为什么需要那个?如果问题是默认行为,你仍然可以像这样做http://jsfiddle.net/xZAGr/12/来防止默认行为。 - Jose Faeti

6

忘记性能-两者之间的任何差异都是微不足道的。

第一种方法要好得多,因为它保持了行为和内容之间的严格分离。

顺便说一下,在赋予事件处理程序时只会产生仅有的性能差异。 在这种情况下,内联调用不必“查找”dom元素,但由于你的jquery选择器是按id选择的(非常有效),所以额外步骤产生的“开销”将非常小。


听起来很有说服力,我正在尝试采用第二种方法。谢谢。 - bingjie2680

3

性能方面,内联调用速度快,因为它会立即触发,而如果您使用jQuery,则需要监听此事件并查找所有附加的处理程序,并按顺序执行它们。但是,使用jQuery,您可以以系统化的方式附加任意数量的处理程序。


是的,它们都有优缺点,这取决于您的使用方式。 - ShankarSangoli
我不相信我能想到任何一个理由来支持将代码嵌入行内。 - BonyT

2

有一种可能性是使用.delegate(),您可以设置特定上下文绑定。这应该比.live()和几个.click()绑定更快,因为delegate的工作原理不同。这里有一个关于这个问题的博客,在SO中还有一个非常好的解释,必读!祝你好运!

HTML

<div id="wrapper">
   <a href="#" id="id1">some content here</a>
   <a href="#" id="id2">some content here</a> 
</div>

Jquery/Javascript

$("#wrapper").delegate("#id1", "click", function(e){
   e.preventDefault();
   //do something here..
});

Jquery Delegate API


好的,我看到这种方法与Jose相似,但比使用switch-case更优雅。帮了很多忙,谢谢。 - bingjie2680
@bingjie2680 是的,完全正确。如果你选择的话,还可以停止事件传播。 - kasdega

0
根据Jose Faeti的回答,这里有两个问题:

问题在于,包含其他元素(例如div或span)的锚标签不会被视为已点击。然而其子元素却可以。

<div id="foo">
    <a class="clickable" href="#a1" name="a1"><div>hello</div></a><br/>
    <div>i don't need to be listened to</div>

    <a class="clickable" href="#a2" name="a2"><div><span>there</span></div></a>
    <div>neither me, only a-tags should be concerned</div>

    <a class="clickable" href="#a3" name="a3">only i am "really" listened to</a>
    <div>more content</div>
</div>

这可能有点丑陋,但在我们现有的应用程序中,这就是当前状态。因此,我按照以下方式改进了相应的JavaScript:

$('#foo').click( function ( event ) {
    event.preventDefault();

    if( $(event.target).hasClass('clickable') ) {
        alert('clicked: ' + event.target.name );
    } else {
        if( $(event.target).closest('a.clickable').length )
            alert('has parent: ' + $(event.target).closest('a.clickable').attr('name') );
    }
});

我的问题是:有没有更好的解决方案?更高效的?它丑陋吗?还是你会做出不同的选择?

干杯


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接