Javascript at a Low Level — V8 Engine: Squeeze Every Cycle with Arrays
“It’s not just about making your current application run faster, it’s about enabling things that you have never been able to do in the past”.
In this series we explore a series of tips to get you writing performance-enhanced JS.
Arrays:
- Use contiguous keys starting at 0 for Arrays.
In Javascript, you have two main categories of arrays, sparse and dense arrays. Sparse arrays have holes, dense arrays don’t.
let sparseArray = [0,1, ,3,4,5]; //no element at index 2
let denseArray = [0,1,2,3,4,5];
let sparseArray2 = new Array(4); //Yep, the constructor creates sparse Arrays.
let denseArray2 = Array.apply(null, Array(4)); //But this is a dense array of undefined elements by forcing the array to become iterable.
Because Javascript supports sparse arrays, the V8 Engine uses two different methods to represent arrays:
- Fast Elements: linear storage for compact key sets for dense arrays.
- Dictionary Elements: Hash table storage for sparse and/or very large arrays.
Thus, because we have different underlying types to represent and store our arrays in machine code, we should prefer dense arrays whenever possible and use contiguous keys. A second tip logically comes from this
2. Don’t delete elements from arrays!
let array = [0,1,2,3];
delete array[2]; //skrt dont do this.
console.log(array); //[1,2, , 4]
Instead, if you have an array that must be altered and accessed multiple times in the future, use Array.prototype.splice();
Splicing will remove an element from an array and takes in two parameters, the index and the number of elements to splice. Splicing, unlike, slicing, mutates the given array and thus is a neat trick to remove one element from an array without converting it to a sparse array.
let array = [0,1,2,3];
array.splice(2,1); //remove from index 2, one element
console.log(array); //[1,2,4]
3. Follow convention and use homogeneous arrays!
Arrays, by convention, should represent homogeneous elements. That is, they should all represent the same thing. Use an object if you need heterogeneous elements. Keep in mind that despite Javascript being dynamically typed, it doesn’t give you reason to abuse it.
let arr = new Array();a[0] = 77; // Allocates - V8 assumes this is a dense array of 32-bit signed integers.a[1] = 88;a[2] = 0.5; // Allocates and converts - V8 realizes it made a mistake, has to change array to double representation (IEEE 64)a[3] = true; // Allocates and converts - V8 messed up again, has to now convert array to a non-numeric array.
If you are forced to fill up an array with heterogeneous elements, let V8 know early on by using an array literal especially with fixed-size small arrays.
let array = [77, 88, 0.5, true]; //V8 knows to not allocate multiple times.
More in this series (coming soon):
- Inline caches
- JIT Compilation of V8
Resources and further reading:
- http://thlorenz.com/talks/demystifying-v8/talk.pdf
- https://v8docs.nodesource.com/node-6.9/
- https://www.youtube.com/watch?v=UJPdhx5zTaw&t=1051s
If this was helpful, please let me know!