Search code examples
javascriptarraysloopsmap-function

Why is Array.from's callback much slower than the map function?


When doing some performance tests today I found that Array.from's callback work pretty slower than running the Array.map function independently.

Tests were done on 32000000 items long array in the following manner.

let t1;
const arr = Array.from(new Array(32000000), (v,i) => {
    if (i === 0) t1 = performance.now();
    return i;
});
let t2 = performance.now();

t2 - t1; // ~4500ms


let arr2 = Array.from(new Array(32000000));
arr2 = arr2.map((v,i) => {
    if (i === 0) t1 = performance.now();
    return i;
});
t2 = performance.now();

t2 - t1; // ~500ms

I always thought the Array.from just runs the map function on itself when the array gets created. The polyfills' code looks alike too. Any idea why is there such a difference in performance?

Tested in Google Chrome 74.0.3729.157, macOS


Solution

  • It's not the mapping function that is slow, it is the Array.from call itself.

    If we remove all the unnecessary variables and conditional statements we get the following simplified benchmark, which returns:

    Chrome 74:

    Array.from with map: 4735.970ms
    Array.map: 166.405ms
    Array.map with from: 5101.585ms
    Array.from: 4999.910ms
    

    Firefox 67:

    
    Array.from with map: 729.000ms
    Array.map: 41.000ms
    Array.map with from: 1150.000ms
    Array.from: 619.000ms
    

    So we can see that the mapping actually takes almost no time, all that is taking the bulk time is the Array.from call.

    I assume Array.from is a lot slower to allocate memory for and create the new Array than the one returned by Array.map just because it is a lot more generic and complex than the map function. Just compare their specs: Array.prototype.map vs Array.from, Array.from seems a lot harder to optimize the compiler for.

    const arr = new Array(32000000);
    
    console.time('Array.from with map');
    const arr1 = Array.from(arr, (v,i) => {
        return i;
    });
    console.timeEnd('Array.from with map');
    
    
    console.time('Array.map');
    const arr2 = arr.map((v,i) => {
        return i;
    });
    console.timeEnd('Array.map');
    
    
    
    console.time('Array.map with from');
    const arr3 = Array.from(arr).map((v,i) => {
        return i;
    });
    console.timeEnd('Array.map with from');
    
    console.time('Array.from');
    const arr4 = Array.from(arr);
    console.timeEnd('Array.from');