【问题标题】:how to speed up javascript/jquery for large inventory file?如何为大型库存文件加速 javascript/jquery?
【发布时间】:2013-10-28 14:07:36
【问题描述】:

我混合使用 jquery 和 javascript 来搜索一堆项目。准确地说是5000+。我在我的网站上使用实时搜索功能,它根据关键字过滤这些项目。但是因为有太多的项目要搜索它滞后,我想加快这个过程。

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/JavaScript">
    $(document).ready(function() {
        $("#filter").keyup(function() {

            // Retrieve the input field text and reset the count to zero
            var filter = $(this).val(), count = 0;

            // Loop through the list
            $(".inventory tr").each(function() {

                // If the list item does not contain the text phrase fade it out
                if ($(this).text().search(new RegExp(filter, "i")) < 0) {
                    $(this).fadeOut();

                    // Show the list item if the phrase matches and increase the count by 1
                } else {
                    $(this).show();
                    count++;
                }
            });

            // Update the count
            var numberItems = count;
            $("#filter-count").text("Number of items = "+count);
        });
    });
</script>

<form id="live-search" action="" class="styled" method="post">
    <fieldset>
        <input type="text" class="text-input" id="filter" value="" />
        <span id="filter-count"></span>
    </fieldset>
</form>

<div class="inventory">
    <table> Stuff </table>
</div>

有什么办法可以加快速度吗?我真的很喜欢这个功能,如果可能的话,我想把它保留在网站上。

【问题讨论】:

  • 您想要进行 5000 次搜索有什么具体原因吗?我的第一个想法是将其减少到更小的数量。
  • 您的目标浏览器是什么?您可以通过不使用 jQuery 来加快速度,而在每个使用 jQuery 的地方。不过,这可能是微不足道的。
  • 如果你想在这样的体积场景中提高速度,首先摆脱 jQuery,然后跳过 RegExp 构造函数并使用 regexp 文字代替。如果您仍然考虑在变量中使用 jquery 缓存 $(this)。像 $this = $(this);

标签: javascript jquery search


【解决方案1】:
  1. jQuery 比 vanilla JS 慢;它的好处是跨浏览器 支持,但你不需要像循环这样的事情 对象

  2. 您正在循环内创建相同的正则表达式模式 每次迭代;在外面声明一次

  3. 将表的副本保存在内存中并在那里搜索会更快,而不是每次都遍历 DOM。也就是说,将数据保存在多维数组中并对其进行扫描;然后更新表格视图

  4. 已经有一个名为 dataTables 的 jQuery 插件可以为您执行此操作@

【讨论】:

  • 感谢dataTables的建议。完全忘记了这一点,尽管我觉得 dataTables 将来可能会很好用。目前,我将其用作一个简单的主题,但 Datatables 可能会在接下来的几周内取代这一切。我现在只想添加一个简单的搜索功能。
【解决方案2】:

这个非 jquery 的小宝贝在大约 50 毫秒内解析了 10000 多个元素。

function foo(){
    var nodes = document.evaluate('//table[@class="inventory"]//tr', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), 
    filterValue = document.getElementById('filter').value;

    if (nodes != null && filterValue != '') {
        var re = new RegExp(filterValue, "i"), count = 0;

        for (var m = 0; m < nodes.snapshotLength; m++){
            var item = nodes.snapshotItem(m);

            if(re.test(item.innerHTML.replace(/<(?:.|\n)*?>/gm, '').trim())){
                count++;
                item.style.display = 'block';
            } else {
                item.style.display = 'none';
            }
        }   

    }
    console.log("Parsed " + nodes.snapshotLength + " elements and matched " + count);
}


function time_my_script(script) {
    var start = new Date();
    script();
    return new Date() - start;
}

window.onload  = function() {
    var filter = document.getElementById('filter');
    filter.onkeyup=function(){ console.log("Time: " + time_my_script(foo) + "ms");} 
}

HTML

<html>
<head>
<script type="text/javascript">
// ...
</script>
</head>
<body>

    <input type="text" id="filter" name="filter" />

    <table class="inventory">
        <tr>
            <td>axxxasd</td>
        </tr>
    </table>
    <table class="inventory">
        <tr>
            <td>axxxasd</td>
        </tr>
    </table>
    <table class="inventory">
        <tr>
            <td>axxxasd</td>
        </tr>
    </table>
    <table class="inventory">
        <tr>
            <td>asd</td>
        </tr>
    </table>
    <!-- ... -->
</body>
</html>

【讨论】:

  • 很棒的剧本。使用 window.performance.now() 会更准确吗?
  • 这个也很棒!我正在玩它,它的速度要快得多!
  • @carter 你可能是对的,我只是把它写成一个简单的提示。我稍后会更新这个例子。
  • @user458474 酷,让我们知道你的成功:)
【解决方案3】:

你可能想debounce搜索方法:

  1. 使其异步以保持 UI 正常运行
  2. 确保一次只运行一个搜索。

【讨论】:

    【解决方案4】:

    我毫不怀疑您的代码目前很慢,您的搜索算法大量使用了 DOM。在键盘上的每个键上,您都从选择器中检索节点列表,这是一个非常糟糕的主意,您不应该在 Web 应用程序中多次检索对 DOM 节点的引用。

    您应该将要在 DOM 之外搜索的数据存储在 javascript 对象中,并且您可能还想使用诸如下划线的节流阀之类的东西来限制可以调用您的搜索函数的速率。

    见:http://underscorejs.org/#throttle,如果不使用下划线,可以从源代码中提取函数。

    【讨论】:

      【解决方案5】:

      为什么不使用 jQuery 内置的 contains 函数?我使用它,它非常快。我使用不区分大小写的 contains 函数版本。

      $(document).ready(function () {
          // to make :contains case insensitive!!!
          $.expr[":"].contains = $.expr.createPseudo(function (arg) {
              return function (elem) {
                  return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
              };
          });
      
          $('#filter').on('input', function () {
              var $t = $(this);
              if ($t.val()) {
                  $('.inventory tr').hide();
                  $('.inventory').find('tr:Contains("' + $t.val() + '")').show();
              }
              else {
                  $(".inventory tr").show();
              }
               $("#filter-count").text("Number of items = " + $(".inventory tr:visible").length);
          });
      });
      

      【讨论】:

      • 谢谢。我会将这段代码放在我的页面中的什么位置?我是否将其替换为您上面提到的过滤器/输入功能?
      • 只需用这个替换您的文档就绪事件处理程序。
      • 这对我不起作用。我不知道为什么。我将编辑上面的函数。
      • 我忘了说我使用的是新的 jQuery。只需将on 更改为bind 即可。
      • 我刚刚尝试过,但仍然无法正常工作。我在表格中找到了我要搜索的所有内容,所以也许这就是原因?
      【解决方案6】:

      我能够将处理时间缩短一半,在某些情况下还不止于此。我正在使用 window.performance.now() 来测试时间。在 Chrome 中,您的脚本对我来说主要是在 140 毫秒左右运行。最长的情况是1400ms。下面的脚本在 50ms-70ms 左右运行,搜索短语越长,脚本似乎越快(低至 10ms)。让我知道你的想法(我循环填充测试数据):

      <!DOCTYPE html>
      <html>
      <head>
      </head>
      <body>
      
      <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
      <script type="text/JavaScript">
      $(document).ready(function(){
          var startTime;
          var endTime;
          var i;
          var htmlString = "";
      
          for(i = 0; i < 5000; i += 1){
              htmlString += "<tr class='inventory'><td>This is my test thing</td></tr>";
          }
      
          $('#myTable').html(htmlString);
      
      
          $("#filter").keyup(function(){
              startTime = window.performance.now();
              // Retrieve the input field text and reset the count to zero
              var filter = $(this).val(),
              count = 0,
              matchedItems = $('tr.inventory td:contains("'+filter+'")'),
              nonMatchedItems = $('tr.inventory td').not(matchedItems),
              numItems = matchedItems.length;
      
              matchedItems.show();
              nonMatchedItems.hide();
      
              $("#filter-count").text("Number of items = "+numItems);
      
              endTime = window.performance.now();
              console.log(endTime - startTime);
          });
      });
      </script>
      <form id="live-search" action="" class="styled" method="post">
          <fieldset>
              <input type="text" class="text-input" id="filter" value="" />
              <span id="filter-count"></span>
          </fieldset>
      </form>
      <div class="inventory">
      <table id="myTable"></table></div>
      
      </body>
      </html>
      

      【讨论】:

      • 效果很好,除了...我将如何放置具有不同阴影和列大小的表格。例如:
      • 为您要执行搜索的任何字段分配一个类,然后相应地更改matchedItems 和nonMatchedItems 选择器。例如`$('tr.inventory td.searchable:contains("'+filter+'")'
      • 好的,我会玩它。谢谢。
      • A3228-12
      猜你喜欢
      • 2016-06-29
      • 1970-01-01
      • 2019-11-24
      • 2019-03-11
      • 2016-04-29
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      相关资源
      最近更新 更多