【问题标题】:Why is this Javascript much *slower* than its jQuery equivalent?为什么这个 Javascript 比它的 jQuery 等价物慢得多?
【发布时间】:2011-10-24 09:26:05
【问题描述】:

我有一个包含大约 500 个项目的 HTML 列表和一个“过滤器”框。当我输入一个字母时,我开始使用 jQuery 过滤列表(时间代码稍后添加):

$('#filter').keyup( function() {
    var jqStart = (new Date).getTime();

    var search = $(this).val().toLowerCase();
    var $list = $('ul.ablist > li');

    $list.each( function() {
        if ( $(this).text().toLowerCase().indexOf(search) === -1 )
            $(this).hide();
        else
            $(this).show();
    } );

    console.log('Time: ' + ((new Date).getTime() - jqStart));
} );

但是,在输入每个字母(尤其是第一个字母)后会有几秒钟的延迟。所以我认为如果我使用纯 Javascript 可能会稍微快一些(我最近读到 jQuery 的 each 函数特别慢)。这是我的 JS 等价物:

document.getElementById('filter').addEventListener( 'keyup', function () {
    var jsStart = (new Date).getTime();

    var search = this.value.toLowerCase();
    var list = document.querySelectorAll('ul.ablist > li');
    for ( var i = 0; i < list.length; i++ )
    {
        if ( list[i].innerText.toLowerCase().indexOf(search) === -1 )
            list[i].style.display = 'none';
        else
            list[i].style.display = 'block';
    }

    console.log('Time: ' + ((new Date).getTime() - jsStart));
}, false );

然而,令我惊讶的是,纯 Javascript 比 jQuery 等价物要慢 10 倍。 jQuery 版本过滤每个字母大约需要 2-3 秒,而 Javascript 版本需要 17 多秒!我在 Ubuntu Linux 上使用 Google Chrome。

这不是为了任何真正重要的事情,所以它不需要超级高效。但是我在这里用我的 Javascript 做的事情真的很愚蠢吗?

【问题讨论】:

  • 我会为这两个选择器计时,看看是不是全部都在那里;我知道 jQuery 选择器的东西已经被调到死了。
  • 缓存list.length 是一回事,尽管它不会产生如此大的差异。据说你的计时方法也不准确。 ejohn.org/blog/accuracy-of-javascript-time
  • @Dave:jQuery 倾向于尽可能多地使用浏览器的原生选择器支持,基本上任何不是 jQuery 特定的选择器都应该由浏览器的原生界面处理,因为它会显着比用 JavaScript 更快。
  • @DaveNewton querySelectorAll = 1 毫秒,$() = 3 毫秒。绝对不是选择器!
  • 尝试用textContent 代替innerText 看看是否有区别。此外,您是否有理由在每个 keyup 事件上运行 'ul.ablist &gt; li'?预计会改变吗?如果是这样,我会使用实时 NodeList。无论哪种方式,我都会将其缓存在处理程序之外。

标签: javascript jquery performance


【解决方案1】:

您可以尝试使用 textContent 而不是 innerText ,我认为它应该更快。此外,分别计时列表生成和循环将判断列表生成是否存在问题。

【讨论】:

  • 谢谢,使用textContent 完全解决了问题 - 现在过滤是即时的! 17,000 毫秒至约 8 毫秒:D
  • +1 = 10。那是铜牌;) @DisgruntledGoat 额外信息:((new Date).getTime - jsStart) 处的外逗号不是绝对必要的,因为您的 JavaScript 表达式是从右到左计算的。另见:developer.mozilla.org/en/JavaScript/Reference/Operators/…
  • @RobW 拿到了徽章。干杯!
【解决方案2】:

另一个提高 javascript 速度的最佳做法是将 list.length 缓存在一个变量中,然后像这样调用该变量:

l = list.length;
for (var i=0;i<l;i++):{ code here}

也许使用jsperf 的时机会更好。

【讨论】:

    【解决方案3】:

    在这里,我对您的代码进行了一些重构:

    var filter = document.getElementById( 'filter' ),
        ablist = document.querySelector( '.ablist' );
    
    filter.addEventListener( 'keyup', function () {
        var re, elems, i, len, elem;
    
        re = RegExp( this.value, 'i' );
        elems = ablist.children;
    
        for ( i = 0, len = elems.length; i < len; i += 1 ) {
            elem = elems[i];       
            elem.style.display = 
                    elem.textContent.search( re ) > -1 ? 'list-item' : 'none';
        }
    }, false );
    

    现场演示: http://jsfiddle.net/MVFxn/

    变化:

    • 使用正则表达式和i 标志,就不需要toLowerCase
    • 如果页面上只有一个 '.ablist' 元素,querySelector 应该是获取它的最快方法(因为一旦找到第一个这样的元素就会中止查询),
    • 没有对 LI 元素的查询,因为 children 属性已经很方便地引用了它们。

    我很想知道这段代码在您的页面上的执行情况...

    【讨论】:

      【解决方案4】:

      我使用while 代替for 并做了一些小的改进。 Here 是最终代码。

      var list = list = document.querySelectorAll('ul.ablist > li');
      document.getElementById('javascriptFilter').addEventListener( 'keyup', function () {
          var jsStart = (new Date).getTime(),
              search = this.value.toLowerCase(),
              i = list.length - 1,
              listItem,
              result;
          while( i >= 0 )
          {
              listItem = list[i];
              if ( listItem.textContent.toLowerCase().indexOf(search) === -1 )
                  listItem.style.display = 'none';
              else
                  listItem.style.display = 'block';
              i--;
          }
      
          result = ((new Date).getTime() - jsStart);
          console.log(['Time: ', result, '<br />'].join(''));
      }, false );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-14
        • 2011-07-07
        • 1970-01-01
        • 1970-01-01
        • 2015-01-26
        • 2016-08-30
        • 2011-03-19
        • 2019-08-14
        相关资源
        最近更新 更多