Home  >  Article  >  Web Front-end  >  JavaScript array evolution and performance analysis examples

JavaScript array evolution and performance analysis examples

小云云
小云云Original
2018-02-12 09:16:401584browse

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. 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.

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 benefits 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

The change occurs in line 3, adding a statement to change the array into a heterogeneous type. The rest of the code remains unchanged. The performance difference shows up, 22 times slower.

Old-style array: read

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");

Time taken: 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");

Time taken: 27ms

Conclusion

The introduction of typed arrays is a big step in the development of JavaScript. Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, these are typed array views, using native endianness (same as native). We can also create custom view windows using DataView. Hopefully there will be more DataView libraries that help us easily manipulate ArrayBuffers in the future.

The evolution of JavaScript arrays is very nice. Now they are fast, efficient, robust, and smart enough in memory allocation.

The above is the detailed content of JavaScript array evolution and performance analysis examples. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn