简体   繁体   中英

Is it possible to optimize Javascript client-side search?

Here is the jQuery/Javascript code I'm using to sort through an unordered list of elements and remove them based on the user's query:

// event binding for the search filter
$('.search-box').keyup(function(){
    var query = $(this).val().toLowerCase(),
        length = query.length;

    $('.friends-list li').each(function(){
        if(query.length > 1 && $(this).find('span').text().toLowerCase().substring(0, length) != query){
            $(this).hide();
        } else {
            $(this).show();
        }
    });
});

Unfortunately, when I get a large number of li elements, this slows down considerably and sometimes hangs on the system. Is there a way to optimize this, or do all of the searching first and then remove the li elements all at one time so the system does not hang?

When I do a server-side search, I can just have a loading spinner and a success callback, but the same does not seem to apply for the client-side.

A couple of tips

Don't fire search on each keyup event. Instead, have a short timer (~200ms) that waits for a next keyup and starts searching if there's none:

 keyup:
      clearTimeout(searchTimer)
      searchTimer = setTimeout(doSearch, 200)

If query.length <=1 your loop can be optimized away, no need to check that on each iteration.

each(li)...find(span) is too much overhead. Try iterating thru spans directly:

$('.friends-list li span').each(function() {
    var p = $(this);
    if(p.text().toLowerCase().indexOf(query) !== 0) {
        p.parent().hide();
    } else {
        p.show();
    }
});

Also note some minor optimizations in the above code.

我还建议使用for循环,因为它明显更快

Deferring DOM updates is an effective way speed up code such as this. Do them all at the end, rather than during your .each() loop.

I'd suggest a delay on the keystrokes such that you don't do the search until the user has stopped typing for some amount of time - say, half a second, though you can try that out and tweak it to taste. Plus I've made a couple of minor changes to your search, eg, if you know the search string is too short you just want to show everything so no need to test each item in a loop in that case.

(function() {
   var timerID = null;

   function doSearch(query) {
     var length = query.length;

     if (length <= 1) {
        $('.friends-list li').show();
     } else {
        $('.friends-list li').each(function(){
           var $this = $(this);
           if($this.find('span').text().toLowerCase()
                                       .substring(0, length) != query)
              $this.hide();
           else
              $this.show();
        });
     }
   } 

   $('.search-box').keyup(function(){
      var searchString = this.value.toLowerCase();

      if (timerID)
         clearTimeout(timerID);

      timerID = setTimeout(function() {
         timerID = null;
         doSearch(searchString);
      }, 500);
   });
)();

我知道这是旧的,但考虑更好的选择器,缓存元素和事件冒泡(这里不适用) - 搜索优化jQuery,你会得到一堆很棒的技巧。

Currently you fire a full search on every key stroke. You may want to wait a small amount of time. Say 0,2 seconds and check if another key has been pressed. The small delay should be okay for the user experience, even hardly noticeable, but if someone is typing a word (pressing keys in rapid succession) this can save you many of those iterations increasing the experienced speed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM