What is the efficient way to create a live search using javascript or jquery?

时光毁灭记忆、已成空白 提交于 2020-04-12 07:31:31

问题


I was making a live search for more than 10000 rows of the dataset. I have mentioned the available dom structure. Although I try to make a live search check every result after a single input, my browser is getting hang. Is there any other efficient way that I can reduce its complexity.

<label class="label">
    <input type="checkbox" name="123" value="">
</label>
<label class="label">
    <input type="checkbox" name="123" value="   General AUX"> General AUX
</label>
<label class="label">
    <input type="checkbox" name="123" value=" Annser"> Annser
</label>
<label class="label">
    <input type="checkbox" name="123" value=" LRIPL"> LRIPL
</label>
<label class="label">
    <input type="checkbox" name="123" value=" Soy Impulse"> Soy Impulse
</label>

** Yes, live search against the DOM** JS code, that I am using for live search

 $(".form-container #filter").keyup(function() {
 var filter = $(this).val(),
                    count = 0;
                if(filter.length>=2){
                // Loop through the comment list
                $(".label").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;
                // $(".popopup-header").text(count + " results");
                //$("#filter-count").text(count + "results"); 
              }
            });

回答1:


There are three different ways you can improve the performance of a live DOM search. (I'm going to take the inherent performance issue with rendering 10000 DOM rows as a given; this answer will only cover the search and its results.) Small details such as using .indexOf() instead of a regexp will help as well, but I'd guess that sort of fine detail is not really your bottleneck.

Make the search faster

Live-searching the DOM is always going to be much, much slower than searching against a simple data object. I'm going to guess that this is, by far, the biggest performance bottleneck you currently have.

It looks like you're only matching against a single string per row, which makes things easier. If you can depend on the order of your rows to never change, then you could get away with searching against a simple array of those strings, and just use the array index to indicate which DOM rows you'll hide or reveal (more about that later) -- but if the row order may change, you'll need to include at least an ID for each so you can match the string to the correct row. So the simplest case might be

var search = function(searchString) {
var searchableRows = ["General AUX", "Ansser", "Etcetera", ...]
var matchedSearch = [];
for (var i=0; i<searchableRows.length; i++) {
  if (searchableRows[i].indexOf(searchString) > -1) {
    matchedSearch[i]=1;
  }
}
// you'll use matchedSearch[] later to control which rows are visible.

Run the search less often

Instead of running the search on every user keystroke, you can debounce the input to guarantee at least n milliseconds between individual searches. Some frameworks have debounce functionality built in, but it's pretty simple to roll your own. The canonical drop-in example is probably this from David Walsh, which I cannot improve on:

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Render the results more quickly

One big DOM operation is less expensive than lots of little DOM operations. And the less you have to change the DOM to get the results you want, the better.

So the simple approach of incrementally hiding or removing DOM rows during the search -- that's out for sure. The two approaches I can think of to handle this are very different, and honestly I'm not sure which would have better performance; which is better may come down to other factors such as how complex the HTML needs to be and whether it has js bindings you need to preserve, how much of it you're comfortable generating within javascript, etc.

So strategy 1: generate the results html as one big string and then drop that into the DOM to replace the original HTML in a single operation:

//assuming you have a filled matchedSearch array from above:
var searchResults = "";
for (var i=0; i<searchableRows.length; i++) {
  if (matchedSearch[i]) {
    searchResults = searchResults + '<label>...'+searchableRows[i]+'</label'>;
  }
}
document.getElementById('ResultsLocation').innerHTML(searchResults);

Or strategy 2 is to take the opposite approach: render the full list once, and minimize how much you change it after the fact for each search. Again, this would be after you've finished generating your matchedSearch array:

var allLabels = $('.label'); // I'm being lazy and depending on jQuery in this example
for (var i=0; i<allLabels.length; i++) {
  if (matchedSearch[i]) {
    allLabels[i].removeClass('hidden');
  } else {
    allLabels[i].addClass('hidden');
  }
}

(There are other possible optimizations in how you display this -- I note you're using .fadeOut() currently; off the top of my head I'm not certain if that's slower than using a CSS class-based animation, but it'd be worth checking. With this many rows you might consider omitting unnecessary visual flourishes anyway.)




回答2:


One step to reduce complexity is to add a timeout before sending the request. If more keys are pressed before it expires, the value to search is appended. That way you don't perform a query for each key stroke.




回答3:


You trigger a search for each keystroke, which is too much. You should delay that search. Doing so using Lodash would be easy. Also, replace the regular expression with indexOf which is faster.

Your new code could be:

 $(".form-container #filter").keyup(_.debounce(function() {
     var filter = $(this).val(),
                count = 0;
            if(filter.length>=2){
            // Loop through the comment list
            $(".label").each(function() {

                // If the list item does not contain the text phrase fade it out
                if ($(this).text().indexOf(filter)) < 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;
            // $(".popopup-header").text(count + " results");
            //$("#filter-count").text(count + "results"); 
          }
}, 400));


来源:https://stackoverflow.com/questions/35039894/what-is-the-efficient-way-to-create-a-live-search-using-javascript-or-jquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!