为什么这个 Javascript 比它的 jQuery 等价物“慢”得多?

发布于 2024-12-11 14:56:05 字数 1384 浏览 0 评论 0原文

我有一个大约 500 个项目的 HTML 列表,上面有一个“过滤器”框。我开始在输入字母时使用 jQuery 来过滤列表(稍后添加计时代码):

$('#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));
} );

但是,输入每个字母(特别是第一个字母)后有几秒钟的延迟。所以我想如果我使用普通的 Javascript 可能会稍微快一些(我最近读到 jQuery 的 each 函数特别慢)。这是我的 JS 等效项:

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 );

然而,令我惊讶的是,普通 Javascript 比 jQuery 等效项慢 10 倍。 jQuery 版本大约需要 2-3 秒来过滤每个字母,而 Javascript 版本需要 17 秒以上!我在 Ubuntu Linux 上使用 Google Chrome。

这并不是真正重要的事情,因此不需要非常高效。但我在这里用 Javascript 做了一些非常愚蠢的事情吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

娇纵 2024-12-18 14:56:05

您可以尝试使用 textContent 而不是 innerText ,我认为它应该更快。另外,分别对列表生成和循环进行计时可以判断列表生成是否存在问题。

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.

忘东忘西忘不掉你 2024-12-18 14:56:05

提高 JavaScript 速度的另一个最佳实践是将 list.length 缓存在变量中并调用该变量,如下所示:

l = list.length;
for (var i=0;i<l;i++):{ code here}

也许可以使用

Another best practice for javascript speed is caching the list.length in a variable and calling the variable like:

l = list.length;
for (var i=0;i<l;i++):{ code here}

And maybe timing with jsperf would be better.

兔小萌 2024-12-18 14:56:05

在这里,我对您的代码进行了一些重构:

var filter = document.getElementById( 'filter' ),
    ablist = document.querySelector( '.ablist' );

filter.addEventListener( 'keyup', function () {
    var re, elems, i, len, elem;

    re = RegExp( this.value, 'i' );
    elems = ablist.children;

    for ( i = 0, len = elems.length; i < len; i += 1 ) {
        elem = elems[i];       
        elem.style.display = 
                elem.textContent.search( re ) > -1 ? 'list-item' : 'none';
    }
}, false );

现场演示: http://jsfiddle.net /MVFxn/

更改:

  • ,则不需要 toLowerCase
  • 使用正则表达式和 i 标志,如果只有一个 '.ablist' 元素在页面上,querySelector 应该是获取它的最快方法(因为一旦找到第一个这样的元素,它就会中止查询),
  • children 以来,没有对 LI 元素的查询code> 属性已经方便地引用它们。

我很想知道这段代码在您的页面上的执行情况...

Here, I've refactored your code a bit:

var filter = document.getElementById( 'filter' ),
    ablist = document.querySelector( '.ablist' );

filter.addEventListener( 'keyup', function () {
    var re, elems, i, len, elem;

    re = RegExp( this.value, 'i' );
    elems = ablist.children;

    for ( i = 0, len = elems.length; i < len; i += 1 ) {
        elem = elems[i];       
        elem.style.display = 
                elem.textContent.search( re ) > -1 ? 'list-item' : 'none';
    }
}, false );

Live demo: http://jsfiddle.net/MVFxn/

Changes:

  • with a regular expression and an i flag, there's no need for toLowerCase,
  • if there is only one '.ablist' element on the page, querySelector should be the fastest way to grab it (since it aborts the query once it finds the first such element),
  • there's no query for the LI elements since the children property already references them conveniently.

I'd love to know how this code performs on your page...

南街九尾狐 2024-12-18 14:56:05

我使用 while 而不是 for 并做了一些小的改进。 这里是最终代码。

var 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 );

I used while instead of for and did some minor improvements. Here is the final code.

var 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 );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文