I have a HTML list of about 500 items and a "filter" box above it. I started by using jQuery to filter the list when I typed a letter (timing code added later):
$('#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));
} );
However, there was a couple of seconds delay after typing each letter (particularly the first letter). So I thought it may be slightly quicker if I used plain Javascript (I read recently that jQuery's each
function is particularly slow). Here's my JS equivalent:
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 );
To my surprise however, the plain Javascript is up to 10 times slower than the jQuery equivalent. The jQuery version takes around 2-3 seconds to filter on each letter, while the Javascript version takes 17+ seconds! I'm using Google Chrome on Ubuntu Linux.
This isn't for anything really important so it doesn't need to be super efficient. But am I doing something really dumb with my Javascript here?
Source: Tips4all
You could try using textContent instead of innerText , I think it should be faster. Also timing the list-generation and loop separately would tell if there is problem in list-generation.
ReplyDeleteAnother best practice for javascript speed is caching the list.length in a variable and calling the variable like:
ReplyDeletel = list.length;
for (var i=0;i<l;i++):{ code here}
And maybe timing with jsperf would be better.
I used while instead of for and did some minor improvements. Here is the final code.
ReplyDeletevar 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 );