为什么使用null进程初始化属性的对象数组更好

时间:2016-06-25 17:22:21

标签: javascript performance

我在js中处理大数组时发现了一些意想不到的结果。在我的测试中,我使用for循环创建了一些类实例的大数组,并且在循环内我将相同的字符串分配给所有对象" x"属性和数组初始化后用这个数组做一些计算。如果构造函数初始化" x" null属性,数组总是处理得更好,即使它做了额外的声明。为什么会这样? 这是我的测试代码。我在chrome上测试过。

function f1() {
    var P = function () {
        this.value = 1
    };
    var big_array = new Array(10000000).fill(1).map((x, index)=> {
        p = new P();
        if (index > 5000000) {
            p.x = "some_string";
        }

        return p;
    });
    big_array.reduce((sum, p)=> sum + p.value, 0);
}

function f2() {
    var P = function () {
        this.value = 1;
        this.x = null;
    };
    var big_array = new Array(10000000).fill(1).map((x, index)=> {
        p = new P();
        if (index > 5000000) {
            p.x = "some_string";
        }

        return p;
    });
    big_array.reduce((sum, p)=> sum + p.value, 0);
}


(function perform(){
    var start = performance.now();
    f1();
    var duration = performance.now() - start;

    console.log('duration of f1  ' + duration);


    start = performance.now();
    f2();
    duration = performance.now() - start;

    console.log('duration of f2 ' + duration);
})()

输出:

duration of f1 14099.85
duration of f2 11694.175000000001

2 个答案:

答案 0 :(得分:3)

在我的Firefox浏览器中,f2的运行速度比f1大约快4倍。原因是Just-in-Time JavaScript编译器试图根据预期的对象结构优化代码。正如mdn所述:

  

幸运的是,对象和属性通常是“可预测的”,在这种情况下,它们的底层结构也是可预测的。 JIT可以依靠它来更快地进行可预测的访问。

如果属性在对象构造函数中被“声明”,那么这个预测当然会更好地工作,这是优化器寻找它的神奇之处。

假设一个结构,“后来”仍然添加一个属性会变得更加昂贵。

但是,有不同的引擎,它们有不同的优化器,所以这个结果在不同的浏览器上可能会有很大不同。但是,在构造函数中包含属性的定义似乎是一种好的做法,即使它们的值尚未知晓。

这将为那些从中受益的引擎带来改进,并且不会在其他引擎上带来大部分性能成本。此外,它还可以提高代码的可读性。

我在Windows 10,FF 47.0和Chrome 51.0.2704.106上进行了测试,得到了以下结果:

        FireFox     Chrome
 --------------------------
 f1      6,400      11,400
 f2      1,700       9,600     

这是几次运行的平均值。

答案 1 :(得分:0)

毫不奇怪,我和我之间没有(或很少)性能差异。这是我得到的结果......

duration of f1  11782.384999999951
duration of f2 11347.524999999965

如果你在浏览器控制台中试过它,&只进行过一次测试,f2可能会针对该特定测试稍微调整一下。