【问题标题】:JS looping and populating array. Which is faster?JS 循环和填充数组。哪个更快?
【发布时间】:2012-08-01 04:09:44
【问题描述】:

我刚刚在 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()-方法在幕后发生了什么,但它一定做对了……对吧?

【问题讨论】:

  • 这不应该工作,因为在 "array2[i] = $(this).get(0).id;"这是一个全局范围,而不是一个 div。
  • 这类问题的存在让我烦恼不已。经过 50 年的编译器技术,程序员仍然必须手动执行这些微优化!

标签: javascript arrays optimization loops


【解决方案1】:

您的设置中的一个缺陷是您的第二个测试实际上不起作用。你写道:

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() 函数确实会导致函数调用增加(以及相关的额外开销),但它们也倾向于更容易表达什么您希望代码执行此操作。

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

【讨论】:

  • 不敢相信我错过了...天哪。重写它,第二个实际上确实最终更快。无论如何,感谢您指出(:
【解决方案2】:

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

在第二个测试中this和第一个不一样。

【讨论】:

    【解决方案3】:

    稍微偏离主题,不是对您的主要问题的直接回答,但是,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 对象定义了一个长度属性,因此将执行以下循环(通常不提供 args

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 不,我的例子只是测试 jQuery 的 each() 与原生 JS for (i=len;i--;){}) 的速度...
      猜你喜欢
      • 1970-01-01
      • 2020-05-30
      • 2015-02-04
      • 1970-01-01
      • 2020-09-11
      • 2021-04-21
      • 2018-12-08
      • 1970-01-01
      相关资源
      最近更新 更多