Author: Senior development engineer of navigation Division of Wang Ming 360 Group
Overview of new features:
At (): Arrays support index queries
Array Group: Array element classification;
Array find from last: Array reverse query
Resizable and Growable Array Buffer: The Array Buffer supports size scaling
Before you begin, briefly describe the context.
These new features were incorporated into stagE3 and STAGe4 status by TC39, an official organization that promotes the advancement of the EMCAScript language. Some of the best proposals, such as Promises, arrow functions, etc., came from this organization. 360 Group, as a member of TC39, is participating in the EMCAScript language promotion activity, so I would like to share the latest language features with you here. Finally, explain stage3 status; Each proposal goes through four stages, stagE1 through STAGe4, before being released into the formal environment of the EMCAScript language. At the stage of StagE3, it was basically recognized by members of the community, and then it was supported by various browser manufacturers, Chrome, Firefox, Safari and so on. Stage4 is now available in all browsers and ready for us to use. This stage concept is usually encountered when configuring the Babel file;
{ "presets": ["es2015"."react"."stage-3"]}Copy the code
A proposal at ()
Arrays support indexed queries
In the past, when we used the [] syntax, we thought arrays and strings supported querying elements by index. Such as:
const arr = [1.2.3.4.5];
console.log(arr[4]) / / 5
Copy the code
It is misleading to think that arr[4] is the fourth element of the query array, but if we try arr[-1], we will find undefined. In EMCAScript, the [] syntax was originally designed to apply to all objects, such as arr[1], and actually only refers to properties of objects with a key of “1”, which any object can have. So writing code like arr[-1] looks valid, but it returns the value of the object’s “-1” attribute.
const arr = [1.2.3.4.5];
console.log(arr[-1]) // undefined
Copy the code
The at() proposal resolves that arrays, strings, and TypedArray cannot be queried directly through indexes. The proposal is currently in SATGE4 and implemented by major browsers. You can copy the code below and try it directly in the browser.
const arr = [1.2.3.4.5];
console.log(arr.at(-2)) / / 4
Copy the code
Comments: The use of arr[arr.Length-1] in past code would have been odd for beginners or developers of other languages, but arr.at(index) is obviously more semantic and a good proposal.
Proposal 2 Array Group
Used for sorting array elements
Add two methods to the Array prototype, groupBy and groupByToMap. The content is relatively simple, directly look at the use case can understand, here is not repeated.
- groupBy
Use cases:
Sort the elements of the array by the number ’40’
let array = [23.56.78.42.11.49]
array.groupBy((item,index) = > {
return item > 40 ? 'Greater than 40' : "Less than 40."
})
// {' less than 40 ': [56, 78, 42, 49], 'less than 40 ': [23,11]}
Copy the code
The groupBy method returns a new anonymous object whose key is the return value of the groupBy callback.
Without the groupBy proposal, we used to implement this:
Array.prototype.groupBy = function(callback) {
const object = {};
for(let i =0; i < this.length; i++) {
let key = callback(this[i],i,this);
if(object[key]) {
object[key].push(this[i])
} else {
object[key] = [this[i]]
}
}
return object;
}
Copy the code
- groupByToMap
The groupByToMap method returns a regular Map with the key of the Map being the value returned by the groupBy callback.
Use cases:
const array = [1.2.3.4.5];
const odd = { odd: true };
const even = { even: true };
array.groupByToMap((num, index, array) = > {
return num % 2= = =0 ? even: odd;
});
// => Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }
Copy the code
Without the groupByToMap proposal, we used to implement this:
Array.prototype.groupByToMap = function(callback) {
const mapObject = new Map(a);for(let i =0; i < this.length; i++) {
let key = callback(this[i],i,this);
if(mapObject.get(key)) {
mapObject.get(key).push(this[i])
} else {
mapObject.set(key,[this[i]])
}
}
return mapObject;
}
Copy the code
Evaluation: In real development, arrays like [1, 2, 3, 4, 5] need to be redeclared to store even and odd numbers.
const obj = { odd: [1.3.5].even: [2.4]}Copy the code
The groupBy proposal returns a null-prototype object, {odd: [1, 3, 5], even: [2, 4]}, without declaring a named object. GroupByToMap returns a regular Map object, which is generally useful.
Proposal 3 Array Find from last
The method of finding an element from the end of an array to the first
Use cases:
In the old JS style, we want to query the elements of the array backwards.
Reverse the array once, then use find to query.
const array = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }];
[...array].reverse().find(n= > n.value % 2= = =1);
// { value: 3 }
Copy the code
Or hang a method on the prototype to implement it:
Array.prototype.findLast = function(callback) {
const len = this.length;
for(let i = len - 1; i > 0; i--) {
if(callback(this[i],i,this)) {
return this[i]
}
}
return -1
}
Copy the code
Array Find from Last
The proposed method, findLast, supports direct reverse lookup of arrays.
array.findLast(n => n.value % 2 === 1); // { value: 3 }
Copy the code
Evaluation: In terms of performance, there is one less array inversion, which is a really impressive optimization. Semantically, there should be a forward query should be reverse query, in line with people’s habits of thinking, generally more practical.
Proposal 4 Resizable and Growable Array Buffer
Extends the ArrayBuffer constructor to take an extra maximum length to allow the buffer to grow and shrink in place.
Before introducing the proposal, you need to take a look at what an ArrayBuffer is, what problems it solves, how and where it can be used. This will make it easier to understand the proposal. The following introduction to ArrayBuffer I have filtered out a lot of the details of the theory, and HOPE to be able to do so without prior knowledge of the students can also read ArrayBuffer at one time.
Array Buffer is a concept that you rarely see in your daily development, but it’s very relevant to us.
An easy understanding of Array buffers is that they allow EMCAScript to manipulate memory space. It was born out of a project, WebGL, which required frequent communication between the browser and the graphics card, whereas the traditional text transfer required the text ‘Hello word’ to be translated into 01010111… Machine languages like this were very performance-intensive, and it was necessary to communicate directly in binary form. Array buffers were born.
const buffer = new ArrayBuffer(32);
Copy the code
This creates a 32-byte memory space called buffer. Some of the conventions, such as the generated ArrayBuffer, cannot be modified directly. Instead, they need to be modified through TypedArray views and DataView views. Uint32Array, DataView is a more flexible view for manipulating ArrayBuffer. Probably because it was originally designed to solve the problem of drawing images, it was called Various views, just remember.
The following are some of the data types supported by TypedArray views
The data type | bytes | meaning | The corresponding C language type |
---|---|---|---|
Int8 | 1 | An 8-bit signed integer | signed char |
Int16 | 2 | 16 – bit signed integer | short |
Int32 | 4 | 32 – bit signed integer | int |
// Generate 12 bytes of memory
const buffer = new ArrayBuffer(12);
// Read the memory space with the Int32Array view
const x1 = new Int32Array(buffer);
// Modify directly
x1[0] = 1;/ / 1
// Read the memory space with the Int8Array view
const x2 = new Uint8Array(buffer);
x2[0] = 2;/ / 2
// the value of x1 changes
x1[0] / / 2
Copy the code
The above code creates two views of the same segment of memory: the 32-bit signed integer (Int32Array constructor) and the 8-bit unsigned integer (Uint8Array constructor). Since the two views correspond to the same memory segment, the modification of the underlying memory by one view affects the other view.
Some understanding of ArrayBuffer
An Array Buffer is a binary Array, or a constructor, but essentially a cache of zeros and ones that serves as a Buffer in memory. Simple understanding is the computer to run, is CPU 0 1 of binary data to be processed, but sometimes the binary data to more quickly and the CPU is in dealing with other tasks, that these data have to back to wait, if the CPU processing tasks quickly, but the data transfer is slow, have to let the CPU idle waiting for data, cause the waste of resources, An ArrayBuffer acts as a buffer memory space. Make this memory space always available for data, not for data to wait with the CPU.
Bottlenecks encountered by the ArrayBuffer
Existing ArrayBuffer there is a problem, when you’re ArrayBuffer space is not enough, need to increase the space you need to call ArrayBuffer a method on the prototype, ArrayBuffer. Prototype. The slice (), use the following
const buffer = new ArrayBuffer(8);
const newBuffer = buffer.slice(0.3);
Copy the code
The above code copies the first three bytes of the buffer object (starting at 0 and ending before the third byte), generating a new ArrayBuffer object.
The slice method actually consists of two steps. The first step is to allocate a new portion of memory and the second step is to copy the original ArrayBuffer object.
This approach works fine once, but in some drawing scenarios, frequently creating new memory and then copying the past can take a significant toll on performance.
Transform ArrayBuffer
That concludes ArrayBuffer and its current bottlenecks. Let’s talk about the proposal to enter stage3.
This proposal extends the constructor of ArrayBuffer by adding the configuration of maximum and minimum scaling length, maximumByteLength. Rewrite the transfer method, can be used to directly transfer the memory space, do not have to copy a copy of memory and move.
The modified ArrayBuffer constructor
class ArrayBuffer {
//options indicates the configuration item
//maximumByteLength Configures the memory scaling length
constructor(byteLength,[ options ]);
// Move the memory
transfer(newByteLength);
// Change the memory size
resize(newByteLength);
// Separate out a non-resizable ArrayBuffer
slice(start, end);
// Determine whether it can be scaled
resizable();
// Get the maximum memory size configured
maximumByteLength();
// Get the current memory size
byteLength();
}
Copy the code
Use cases:
Declare a 1024 byte memory and set the maximum memory size to 1024 square
// Add a configuration item, maximumByteLength, to allow maximum memory length up to 1024 square
let rab = new ArrayBuffer(1024, { maximumByteLength: 1024 ** 2 });
// The current memory length is 1024 bytes
assert(rab.byteLength === 1024);
// Contains a maximum of 1024 square bytes
assert(rab.maximumByteLength === 1024 ** 2);
// The length can be changed in place
assert(rab.resizable);
// Change the memory size
rab.resize(rab.byteLength * 2);
// The memory length changed
assert(rab.byteLength === 1024 * 2);
Copy the code
Transfer is to move the memory
let ab = rab.transfer(1024);
Copy the code
It’s 1024 bytes starting at 0
assert(rab.byteLength === 0);
assert(rab.maximumByteLength === 0);
Copy the code
Above is the original memory (RAB) being separated and the memory cleared.
// Memory is transferred to ABassert(! ab.resizable); assert(ab.byteLength ===1024);
Copy the code
The memory was successfully transferred to AB
SharedArrayBuffer
SharedArrayBuffer is, as its name implies, an ArrayBuffer that can be shared
In the ArrayBuffer proposal, SharedArrayBuffer has also been changed to support memory growth.
Let’s take a look at what SharedArrayBuffer is.
There are some calculation tasks in EMCAScript that are usually placed in worker threads. Each worker thread is isolated from each other and communication between them needs to be completed via postMessage.
In addition to the number of strings, binary data can also be communicated, but the binary data needs to be copied and then used as postMessage to pass to another thread. The efficiency will be low when there is a large amount of data. Therefore, someone proposed SharedArrayBuffer that can be shared in ES2017. The main thread of JS and worker thread can share this memory space and simultaneously read and write data, avoiding performance loss caused by binary data replication.
In the actual scenario, a SharedArrayBuffer is created in the main thread and the memory address is sent to the worker thread via postMessage
/ / main thread
// create 1KB shared memory
const sharedBuffer = new SharedArrayBuffer(1024);
// The main thread sends the address of shared memory
w.postMessage(sharedBuffer);
Copy the code
The worker thread accepts the shared address —- SharedArrayBuffer from the host thread without having to copy the same binary address. Improved performance by sharing addresses.
/ / Worker thread
onmessage = function (ev) {
// The data shared by the main thread is 1KB of shared memory
const sharedBuffer = ev.data;
// Create views on shared memory for easy reading and writing
const sharedArray = new Int32Array(sharedBuffer);
// ...
};
Copy the code
The ArrayBuffer proposal also extends SharedArrayBuffer to allow it to increase memory. Unlike ArrayBuffer, SharedArrayBuffer does not support reducing memory. Obviously, if you reduce memory, It is likely to affect other programs that are sharing the memory.
Here are the constructors for SharedArrayBuffer. The resize in the ArrayBuffer constructor, named grow, also shows the difference.
class SharedArrayBuffer {
// Configure maximumByteLength like ArrayBuffer
constructor(byteLength, [ options ]);
// Memory can only be increased, not shortened
grow(newByteLength);
// Separate a non-growing SharedArrayBuffer.
slice(start, end);
// Determine whether memory can be expanded
growable();
// Get the maximum memory size
maximumByteLength();
// Get the current memory size
byteLength();
}
Copy the code
At present, the ArrayBuffer proposal encounters one obstacle. In real scenarios, there may be multiple threads that need to expand the memory. According to the current design, the memory needs to be occupied first and then expanded or reduced to the target memory, but in real scenarios, there may be insufficient memory, which will cause resource robbery. So the problem of how to allocate memory resources still needs to be solved.
The end of the
If you are interested in these proposals, please leave a comment.
So those are the four proposals.
If it is helpful to you, I hope every friend points like forwarding, your encouragement is we continue to promote the new features of JS language power.
Xiaoming
Censor: Jay