JS循环和填充数组。哪个更快?

时间:2009-08-11 12:34:06

标签: javascript arrays optimization loops

我刚刚在GoogleTalks上看到了Nicholas Zakas of Yahoo的视频,谈论加快您的网站速度。他提到的一件事是以相反的顺序进行循环,以跳过两个比较中的一个:for (i = len; i--;) {}

他说要远离for each的JS库实现。只是为了好玩,我想我会尝试一下。事实证明他错了。

var array1 = new Array();
var array2 = new Array();
var start = 0;
var finished = 0;
start = (new Date).getTime();
$("#newDivTest").children().each(function(i){ 
    array1[i] = $(this).get(0).id;
});
finished = (new Date).getTime() - start;
alert(finished);

start = (new Date).getTime();
var len = $("#newDivTest").children().length;

for (i = len; i--;) {
    array2[i] = $(this).get(0).id;
}
finished = (new Date).getTime() - start;
alert(finished);

newDivTest包含1000个空div,其id从“0”开始并上升到“999”。另一个注意事项是$(this).get(0).id由于某种原因比$(this).attr("id")快约3倍,有人知道为什么吗?

对于FF3.5,结果为“7”和“45”,IE7给出“30”和“45”,Chrome2给出“4”和“17”,Opera10给出“16”和“16”,以及最后,Safari4给出“4”和“16”。

因此,尼古拉斯最难对付的方法实际上几乎在所有情况下都更快。

我不够聪明,不知道jQuery的each() - 方法幕后发生了什么,但它必须做正确的事......对吗?

4 个答案:

答案 0 :(得分:7)

您的设置中的一个缺陷是您的第二次测试实际上无法正常工作。你写道:

for (i = len; i--;) {
    array2[i] = $(this).get(0).id;
}

但是this没有定义,所以整个操作都会失败。你必须做类似的事情:

var children = $("#newDivTest").children();
for (i = children.length; i--;) {
    array2[i] = children.get(i).id;
}

这是一个比性能更紧迫的问题:尽管调用类似jQuery的.each()函数会导致添加函数调用(以及相关的额外开销),但它们也倾向于使表达内容更容易你想要代码。

引用迈克尔·杰克逊:“程序优化的第一条规则:不要这样做。程序优化的第二条规则(仅限专家!):不要这样做。”

答案 1 :(得分:1)

您的测试不是在做不同的事情吗?

在第二次测试中,this与第一次测试不同。

答案 2 :(得分:1)

稍微偏离主题,而不是直接回答你的主要问题但是,jQuery的每个方法都是这样实现的(jQuery 1.3.2)

jQuery.extend({

        /* ... Code taken out for brevity ... */

    // args is for internal usage only
    each: function( object, callback, args ) {
        var name, i = 0, length = object.length;

        if ( args ) {
            if ( length === undefined ) {
                for ( name in object )
                    if ( callback.apply( object[ name ], args ) === false )
                        break;
            } else
                for ( ; i < length; )
                    if ( callback.apply( object[ i++ ], args ) === false )
                        break;

        // A special, fast, case for the most common use of each
        } else {
            if ( length === undefined ) {
                for ( name in object )
                    if ( callback.call( object[ name ], name, object[ name ] ) === false )
                        break;
            } else
                for ( var value = object[0];
                    i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
        }

        return object;
    }

        /* ... Code taken out for brevity ... */

        );

如您所见,callback函数应用于object的每个属性。 jQuery对象定义了一个length属性,因此将执行以下循环(通常,不提供args

for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}

在每次迭代中,回调函数会将范围链长度增加1,因此需要更长的时间来解析对象属性的引用。

答案 3 :(得分:1)

我注意到你的问题是“JS循环和填充数组。哪个更快?”,但你的例子实际上是测试各种JQuery选择器的速度,对吧?您可能有兴趣查看:http://mootools.net/slickspeed/

至于“JS循环和填充数组。哪个更快?”,请参见:http://blogs.oracle.com/greimer/resource/loop-test.html