skip to Main Content

For javascript which one is faster?

a.unshift("new first value");

vs

for(i=a.length; i>0; i--) a[i] = a[i-1];
a[0] = "new first value";

vs

a[5] = a[4];
a[4] = a[3];
a[3] = a[2];
a[2] = a[1];
a[1] = a[0];
a[0] = "new first value";

Well, of course, assigning values by hand is unpractical.
But there would be cases that your array has very few items that you can assign it with your hand and it’s in a loop that would repeat it millions of times.
So I just included it.

Then the main question is:

  1. Is there any performance difference between first two cases?
  2. And can third one be faster than both of them

3

Answers


  1. It depends but in general, directly assigning values by hand tends to be faster than using methods like unshift() or looping to assign values to an array. This is because direct assignment involves fewer operations and less overhead compared to shifting existing elements or iterating over the array.

    Login or Signup to reply.
  2. Seems the manual assignment is good with a small number of items only, then unshift takes the place.

    ` Chrome/123
    -------------------------------------------------------------------------------------
    >                 n=5       |       n=50        |      n=500       |      n=5000     
    unshift      2.02x x10m 704 |  1.00x   x1m   96 |  1.00x   x1m 521 |  1.00x x100k 426
    splice       2.03x x10m 706 |  1.38x   x1m  132 |  1.18x   x1m 614 |  1.24x x100k 529
    loop         1.16x x10m 404 |  3.05x   x1m  293 |  5.34x x100k 278 |  2.63x  x10k 112
    manual       1.00x x10m 348 |  1.13x  x10m 1085 |  1.52x   x1m 794 | 11.17x  x10k 476
    copyWithin   6.87x  x1m 239 | 15.21x x100k  146 | 24.95x  x10k 130 | 30.75x   x1k 131
    -------------------------------------------------------------------------------------
    https://github.com/silentmantra/benchmark `
    

    In Firefox splice is the fastest:

    ` Firefox/124
    ------------------------------------------------------------------------------
    >                 n=5       |     n=50      |      n=500      |     n=5000    
    splice       1.71x x10m 580 | 1.30x x1m 161 | 1.03x x100k 251 | 1.00x x10k 208
    unshift      1.42x x10m 482 | 1.15x x1m 143 | 1.00x x100k 244 | 1.30x x10k 271
    copyWithin   1.43x x10m 487 | 1.86x x1m 231 | 1.64x x100k 401 | 1.40x x10k 291
    loop         1.67x x10m 568 | 3.57x x1m 443 | 2.30x x100k 562 | 2.50x x10k 521
    manual       1.00x x10m 340 | 1.00x x1m 124 | 1.68x x100k 410 | 3.18x x10k 661
    ------------------------------------------------------------------------------
    https://github.com/silentmantra/benchmark `
    
    let $length = 5;
    let b = Array.from({length:$length}, (_,i) => i+1);
    
    // @benchmark manual
    const genAssign = length => new Function('a', Array.from({length}, (_, i) => `a[${length - i}] = a[${length - i - 1}]`).join(';'))
    
    const assign = genAssign($length);
    // @run
    a = b.slice();
    assign(a);
    a[0] = "new first value";
    
    // @benchmark loop
    a = b.slice();
    for(i=a.length; i>0; i--) a[i] = a[i-1];
    a[0] = "new first value";
    
    // @benchmark unshift
    a = b.slice();
    a.unshift("new first value");
    
    // @benchmark splice
    a = b.slice();
    a.splice(0, 0, "new first value");
    
    // @benchmark copyWithin
    a = b.slice();
    a.length++;
    a.copyWithin(1, 0, a.length);
    a[0] = "new first value";
    
    
    /*@skip*/ fetch('https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js').then(r => r.text().then(eval));
    Login or Signup to reply.
  3. You could create a function dynamically that makes all the individual assignments, using the Function constructor.

    The bigger the array, the more dramatic the difference in running time. Here is a script that creates an array with one million entries, and the dynamic function with as many assignments (+ 1). It then calls the function once and also unshift

    // Test with an array with a million values
    const a = [...Array(1e6).keys()];
    const b = [...Array(1e6).keys()];
    // Dynamically create a function that makes all assignments as individual JS statements
    const f1 = new Function("a", "value", a.map((_, i) => 
        `a[${i+1}]=a[${i}];`
    ).reverse().join("n") + "na[0]=value;");
    // ...and the alternative that uses the native unshift method
    function f2(a, value) { a.unshift(value); }
    
    function timeit(f, a) {
      const start = performance.now();
      f(a, "x");
      console.log(performance.now() - start);
    }
    
    timeit(f1, a);
    timeit(f2, b);
    // repeat with the same arrays:
    a.shift(); b.shift();
    timeit(f1, a);
    timeit(f2, b);
    // Verify the results are identical
    console.log(JSON.stringify(a) === JSON.stringify(b) ? "same" : "different");

    Clearly unshift wins once the array size becomes significant. This should not come as a surprise as once the JS call of unshift is made, no more JS code is concerned, and the actual shifting can rely on compiled C code.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search