2

我混合使用 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>

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

4

6 回答 6

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

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

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

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

于 2013-10-28T14:18:05.297 回答
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>
于 2013-10-28T15:23:32.217 回答
1

I have no doubt that your code is currently slow, your search algorithm make extensive use of the DOM. At each key up on the keyboard you retrieve a list of node from a selector, this a very bad idea, you should not retrieve reference to DOM nodes more than once in a web application.

You should store the data you want to search outside of the DOM in a javascript object, and you might want also to use something like underscore's throttle to limit the rate at which your search function can be called.

See: http://underscorejs.org/#throttle, you could extract the function from the source code if you do not use underscore.

于 2013-10-28T14:25:52.280 回答
1

您可能想要消除搜索方法的抖动:

  1. 使其异步以保持 UI 功能
  2. 确保一次只运行一个搜索。
于 2013-10-28T14:17:56.873 回答
0

为什么不使用 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);
    });
});
于 2013-10-28T14:17:44.713 回答
0

我能够将处理时间缩短一半,在某些情况下还不止于此。我正在使用 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>
于 2013-10-28T14:52:07.900 回答