Before we start, we need to declare that this article is not intended to explain the basics of JavaScript arrays, nor will it cover syntax and use cases. This article talks more about memory, optimization, syntax differences, performance, and recent evolutions. This article mainly introduces the evolution and performance analysis of JavaScript arrays. This article talks more about memory, optimization, syntax differences, performance, and recent evolution. Friends in need can refer to it, I hope it can help everyone.
Before using JavaScript, I was already quite familiar with C, C++, and C#. Like many C/C++ developers, my first impression of JavaScript was not a good one.
Array is one of the main reasons. JavaScript arrays are not contiguous and are implemented like hash-maps or dictionaries. I feel like this is a bit of a B-level language, and the array implementation is simply not appropriate. Since then, JavaScript and my understanding of it have changed, a lot.
Why JavaScript arrays are not real arrays
Before talking about JavaScript, let’s first talk about what Array is.
An array is a contiguous series of memory locations used to hold certain values. It's important to note the emphasis, "continuous" (or contiguous).
The above figure shows how arrays are stored in memory. This array holds 4 elements, each element is 4 bytes. In total, it occupies 16 bytes of memory area.
Suppose we declare tinyInt arr[4];, the address of the allocated memory area starts from 1201. Once you need to read arr[2], you only need to get the address of arr[2] through mathematical calculations. To calculate 1201 + (2 X 4), just start reading directly from 1209.
#Data in JavaScript is a hash map, which can be implemented using different data structures, such as linked lists. So, if you declare an array in JavaScript var arr = new Array(4), the computer will generate a structure similar to the one shown above. If the program needs to read arr[2], it needs to traverse the addressing starting from 1201.
The difference between the above rapid JavaScript arrays and real arrays. Obviously, mathematical calculations are faster than traversing a linked list. This is especially true for long arrays.
The evolution of JavaScript arrays
I wonder if you remember the days when we were so envious of the 256MB computer our friends bought? Today, 8GB of RAM is everywhere.
Similarly, the JavaScript language has also evolved a lot. From V8 and SpiderMonkey to TC39 and the growing number of web users, huge efforts have made JavaScript a world-class necessity. Once you have a huge user base, performance improvement is naturally a hard requirement.
In fact, modern JavaScript engines will allocate contiguous memory for arrays - if the array is homogeneous (all elements are of the same type). A good programmer will always ensure that the array is homogeneous so that the JIT (just-in-time compiler) can read the elements using c compiler-style calculations.
However, once you want to insert an element of another type into a homogeneous array, the JIT will deconstruct the entire array and recreate it in the old way.
So, if your code is not too bad, JavaScript Array objects still remain true arrays behind the scenes, which is extremely important for modern JS developers.
In addition, arrays have evolved more following ES2015/ES6. TC39 decided to introduce typed arrays (Typed Arrays), so we have ArrayBuffer.
ArrayBuffer provides a continuous memory for us to operate at will. However, directly operating memory is still too complex and low-level. So there is a view that handles ArrayBuffer. There are already a few views available, and more will be added in the future.
var buffer = new ArrayBuffer(8); var view = new Int32Array(buffer); view[0] = 100;
High-performance, efficient typed arrays were introduced after WebGL. WebGL workers encounter a huge performance problem, namely how to efficiently handle binary data. Alternatively, you can use SharedArrayBuffer to share data between multiple Web Worker processes to improve performance.
Going from a simple hash map to SharedArrayBuffer, that's pretty cool, right?
Old-style arrays vs typed arrays: Performance
We have discussed the evolution of JavaScript arrays before, now let’s test how much benefit modern arrays can bring us. Here are some micro-test results I ran on a Mac using Node.js 8.4.0.
Old-style array: insert
var LIMIT = 10000000; var arr = new Array(LIMIT); console.time("Array insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("Array insertion time");
Time taken: 55ms
Typed Array:插入 var LIMIT = 10000000; var buffer = new ArrayBuffer(LIMIT * 4); var arr = new Int32Array(buffer); console.time("ArrayBuffer insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("ArrayBuffer insertion time");
Time taken: 52ms
Rub, what do I see? Are old-style arrays and ArrayBuffer equally performant? No no no. Remember, as mentioned earlier, modern compilers are smart enough to internally convert traditional arrays of the same element type into memory-contiguous arrays. This is exactly the case with the first example. Despite the use of new Array(LIMIT), the array still exists as a modern array.
Then modify the first example and change the array to a heterogeneous type (the element types are not completely consistent) to see if there is a performance difference.
旧式数组:插入(异构) var LIMIT = 10000000; var arr = new Array(LIMIT); arr.push({a: 22}); console.time("Array insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("Array insertion time");
Time taken: 1207ms
改变发生在第 3 行,添加一条语句,将数组变为异构类型。其余代码保持不变。性能差异表现出来了,慢了 22 倍。
旧式数组:读取
var LIMIT = 10000000; var arr = new Array(LIMIT); arr.push({a: 22}); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } var p; console.time("Array read time"); for (var i = 0; i < LIMIT; i++) { //arr[i] = i; p = arr[i]; } console.timeEnd("Array read time");
用时:196ms
Typed Array:读取 var LIMIT = 10000000; var buffer = new ArrayBuffer(LIMIT * 4); var arr = new Int32Array(buffer); console.time("ArrayBuffer insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.time("ArrayBuffer read time"); for (var i = 0; i < LIMIT; i++) { var p = arr[i]; } console.timeEnd("ArrayBuffer read time");
用时:27ms
结论
类型化数组的引入是 JavaScript 发展历程中的一大步。Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,这些是类型化数组视图,使用原生字节序(与本机相同)。我们还可以使用 DataView 创建自定义视图窗口。希望未来会有更多帮助我们轻松操作 ArrayBuffer 的 DataView 库。
JavaScript 数组的演进非常 nice。现在它们速度快、效率高、健壮,在内存分配时也足够智能。
相关推荐:
The above is the detailed content of JavaScript Array Evolution and Performance Analysis. For more information, please follow other related articles on the PHP Chinese website!