【问题标题】:How to optimize this simple jquery code?如何优化这个简单的 jquery 代码?
【发布时间】:2011-11-18 20:40:58
【问题描述】:

我正在尝试学习一些关于优化我的 jQuery 代码的知识...

有没有办法改进下面的代码,使变量$selected在函数外声明,但仍然可以访问,这样就不用每次都遍历DOM了?

或者这段代码是否已尽可能优化?

或者...我想我可能误解了 jquery DOM 遍历发生的方式和时间。

$('#full-width-layout_c1_col-1-1_1').on(
    'mouseenter mouseleave click', 
    'a.project_open, a.song_open', 
    function(e) {
        var $selected = $(this).closest('tr').find('div');
        if (e.type == 'mouseenter') {
            $selected.addClass("hovered");
        }
        else if (e.type == 'mouseleave'){
            $selected.removeClass("hovered");
        }
        else if (e.type == 'click'){
            $selected.addClass('opened');
        }
    }
);

【问题讨论】:

  • 对不起,我忽略了性能优化要求。我已经删除了我的答案
  • js 代码看起来不错,进一步优化(可能)需要您发布 HTML 本身。
  • HTML 都是通过 jquery 模板动态生成的,并通过创建表的 json 数据提供...这就是为什么当我悬停时我需要向上遍历特定行然后再次向下遍历 div 和给它添加一个类。我想这真的是我所能做的优化,除非 .data 方法最终成为赢家。

标签: javascript jquery optimization


【解决方案1】:

如果您想要在 DOM 元素中存储任意数据时的每一点性能,请不要使用jQuery.data()。那会表现得更好:

var $selected = this.closestdiv;

if(!$selected) { // first time
    $selected = $(this).closest('tr').find('div');
    this.closestdiv = $selected;
}

通过这个简单的基准测试http://jsperf.com/jquerydata/4,您可以看到直接在 DOM 上存储数据比使用jQuery.data() 更快。在我的机器上使用 jQuery.data() 比直接存储数据慢 97%。同样,公平的警告 - jQuery.data() 有一定的开销,因为它试图聪明地处理事情并防止潜在的内存泄漏。

【讨论】:

  • 确实,我体验到它的速度是原来的 45 倍!很高兴知道。
  • .data 对我来说慢了 98%,所以普通存储实际上快了 4900%(快了 50 倍)。
  • 神奇的东西 WTK...非常感谢这个..它真的让我大开眼界!对您和 pimvdb 的巨大支持让我找到了一个可以在我的应用程序中工作的解决方案,而不仅仅是在我提供的示例代码中。抱歉 pimvdb 但我为此向 WTK 提供了“打勾”。你们俩干杯!
【解决方案2】:

您可以使用某种缓存 - 当单击元素时,将 $selected 作为数据存储到元素中,以便下次从元素中获取 $selected,而不是通过执行 DOM 遍历:

var $selected = $(this).data("closestdiv");

if(!$selected) { // first time
    $selected = $(this).closest('tr').find('div');
    $(this).data("closestdiv", $selected);
}

【讨论】:

  • 会很好,除了 jQuery.data() 与直接存储在 DOM 节点上相比慢得可怕。另一方面,这是有原因的 - 防止内存泄漏。
  • 乍一看这看起来不错...所以,澄清一下,使用上述技术,我可以在悬停、鼠标和单击时分配数据...然后当事件再次发生时,它不必遍历 DOM,使重复悬停/点击更快?如果我正确理解这一点,那正是我正在寻找的。​​span>
  • @gordyr:是的,你是对的。请注意,当您更改 DOM 时,这不会反映出来,因为在第一次之后不再进行任何 DOM 遍历。另外,根据@WTK .data 仍然很慢,但我必须测试什么更重。
  • @gordyr:好的缓存在 Chrome 上大约快 50%:jsperf.com/using-cache-to-avoid-dom-traversal
  • 备份我关于数据缓慢的观点:jsperf.com/jquerydata/4 如果您没有对 div 做一些会触发内存泄漏的奇怪事情,请查看我的答案以获得更好的解决方案。
【解决方案3】:

由于您选择的是 ID,并且我假设您只有一个具有此 ID 的元素,因此您可以在事件处理程序之外使用它:

var $selected = $('#full-width-layout_c1_col-1-1_1').closest('tr').find('div');

这还假设不会进行任何可能改变上述语句返回的内容的 DOM 操作。

编辑:没关系。我看错了。对不起。

【讨论】:

    【解决方案4】:

    如果没有看到您的 HTML,很难确定,但我怀疑您无法查找要修改的 DIV,因为单击的每个锚点都不同。既然如此,每次都需要从点击/悬停的元素遍历 DOM。

    【讨论】:

    • 你完全正确,我的道歉我应该在我的问题中更具体
    【解决方案5】:

    这不是答案,但减少代码的机会很少:

    $('#full-width-layout_c1_col-1-1_1').on(
        'mouseenter mouseleave click', 
        'a.project_open, a.song_open', 
        function(e) {
            var $selected = $(this).closest('tr').find('div');
            if (e.type === 'click'){
                $selected.addClass('opened');
            } else {
                $selected.toggleClass('hovered');
        }
    );
    

    【讨论】:

      【解决方案6】:

      你可以使用闭包:

      (function () {//scoping function
          var $selected = $(this).closest('tr').find('div');
      
          $('#full-width-layout_c1_col-1-1_1').on(
          'mouseenter mouseleave click', 
          'a.project_open, a.song_open', 
          function(e) {
              if (e.type == 'mouseenter') {
                  $selected.addClass("hovered");
              }
              else if (e.type == 'mouseleave'){
                  $selected.removeClass("hovered");
              }
              else if (e.type == 'click'){
                  $selected.addClass('opened');
              }
          }
          );
      
      
      }()); //end scoping function
      

      这将使对 div 的搜索只发生一次。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-25
        • 1970-01-01
        • 1970-01-01
        • 2017-07-13
        • 1970-01-01
        相关资源
        最近更新 更多