Ecma TC39 has updated the ECMAScript standard once a year in recent years. The following features are finished. Now let’s experience the new features of ES2020.

A: Promise. AllSettled

Promise. All defects

Promise.all is known to have the ability to execute asynchronous tasks concurrently. The biggest problem with this is that if one of the tasks fails, all the tasks hang, and the Promise goes straight into reject.

Picture this: Use Promise. All to consign three interfaces. If any of the interfaces fails, reject will render all of the data in the three regions of the page. Since any reject goes into a catch callback, this is clearly unacceptable, as follows:

Promise.all([
    Promise.reject({code: 500, msg: 'Service exception'}), Promise.resolve({ code: 200, list: []}), Promise.resolve({code: 200, list: []})]).then((ret) => {// If one of the tasks is reject, the callback is not executed. RenderContent(ret); }). Catch ((error) => {// error: {code: 500, MSG:"Abnormal service"}})Copy the code

This is a big pity or pity. We need a mechanism. If a concurrent task is fulfilled, no matter the task is normal or abnormal, the corresponding state (depressing or rejected) and result (business value or reason) will be returned. In then, the desired business logic results can be filtered by filter, which maximizes the accessibility of the current state of the business. Promise.allsettled is the solution to this problem.

Promise.allSettled([
    Promise.reject({code: 500, msg: 'Service exception'}),
    Promise.resolve({ code: 200, list: []}),
    Promise.resolve({code: 200, list: []})
])
.then((ret) => {
    /*
        0: {status: "rejected"Reason: {... }} 1: {status:"fulfilled", the value: {... }} 2: {status:"fulfilled", the value: {... RenderContent(ret. Filter ((el) => {}} */ / Filter out the rejected state, RenderContent(ret. Filter (el) => {returnel.status ! = ='rejected';
    }));
});

Copy the code

2: Optional Chaining

Optional chains allow us to query multi-tiered objects without the need for redundant pre-validation.

In daily development, we often encounter such queries

var name = user && user.info && user.info.name;
Copy the code

Or this

var age = user && user.info && user.info.getAge && user.info.getAge();
Copy the code

Uncaught TypeError: Cannot read property Uncaught TypeError: Cannot read property… This kind of error, this is very likely to kill your entire application.

With Optional Chaining, the above code becomes

var name = user? .info?.name;Copy the code
var age = user? .info?.getAge?.();Copy the code

Optional chain? Indicates that if the expression to the left of the question mark has a value, the field following the question mark continues to be queried. As can be seen from the above, using the optional chain can greatly simplify the similar tedious pre-check operation, and it is safer.

3. Nullish coalescing Operator

When we query for an attribute, we often encounter that a default value is set if the attribute is not available. For example, query the player level in the following code.

var level =  user.data.level || 'No level yet';
Copy the code

In JS, an empty string, 0, is automatically converted to false when the logical operator is evaluated. In the above code, if the player level itself is level 0, the variable level will be assigned a string with no level. This is a logical error.

/ / {/ /"level": null // } var level = user.level ! == undefined && user.level ! == null ? user.level :'No level yet';
Copy the code

Let’s see what happens with the null-value merge operator. Okay

/ / {/ /"level": 0   
// }
var level = user.level ?? 'No level yet'; // level -> 0


// {
//   "an_other_field": 0   
// }
var level = user.level ?? 'No level yet'; // level -> 'No level yet'

Copy the code

With null value merge operation in the premise of correct logic, the code is more concise.

The null-value merge operator, combined with optional chains, makes it easy to handle multi-level queries and assign defaults.

var level = user.data? .level ??'No level yet';
Copy the code

4: dynamic – the import

The On-demand import proposal has been around for a few years now, and is finally making it into the FORMAL ES specification. “On demand” is more appropriate. Modern front-end packaging resources are increasing, packaging into several M JS resources has become a normal, but often front-end application initialization does not need to load the full logical resources, in order to speed up the first screen rendering, many times are loaded on demand, such as lazy loading images. The on-demand logic resources are loaded in an event callback.

el.onclick = () => { import(`/path/current-logic.js`) .then((module) => { module.doSomthing(); }) .catch((err) => { // load error; })}Copy the code

Of course, WebPack now has good support for this feature.

Five: globalThis

Javascript has different ways of retrieving global objects in different environments, such as node via global, Web via Window, self, etc. Some even get global objects through this, but this is extremely dangerous, this is extremely complex in JS, It relies heavily on the current execution context, which undoubtedly increases the complexity of obtaining global objects.

In the past, global objects can be obtained through a global function

var getGlobal = function () { 
  if(typeof self ! = ='undefined') { return self; } 
  if(typeof window ! = ='undefined') { return window; } 
  if(typeof global ! = ='undefined') { return global; } 
  throw new Error('unable to locate global object'); 
}; 

var globals = getGlobal(); 

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis
Copy the code

The purpose of globalThis is to provide a standardized way to access global objects. With globalThis, you can access global objects in any context at any time.

Six: BigInt

In Js, the Number type can only safely represent values from -(2^53-1) to 2^53-1, that is, number. MIN_SAFE_INTEGER to number. MAX_SAFE_INTEGER.

var num = Number.MAX_SAFE_INTEGER; // -> 9007199254740991 num = num + 1; Num = num +1; 9007199254740992 9007199254740992 // Two different values, but returnedtrue
9007199254740992 === 9007199254740993  // -> true
Copy the code

To solve this problem, ES2020 provides a new data type: BigInt. There are two ways to use BigInt:

  1. Add after the integer literaln.
var bigIntNum = 9007199254740993n;
Copy the code
  1. useBigIntFunction.
var bigIntNum = BigInt(9007199254740);
var anOtherBigIntNum = BigInt('9007199254740993');
Copy the code

With BigInt, we can safely compute large integer types.

var bigNumRet = 9007199254740993n + 9007199254740993n; // -> -> 18014398509481986n

bigNumRet.toString(); // -> '18014398509481986'
Copy the code

Note:

  1. BigInt is a new type of primitive.
typeof 9007199254740993n; // -> 'bigint'
Copy the code
  1. Avoid calling functions whenever possibleBigIntMethod to instantiate a large integer. Because the parameter literal is actually an instantiation of type Number, numbers outside the safe range can cause loss of precision.

Seven: String. Prototype. MatchAll

Consider the following code

var str = '< text > javascript < / text > < text > regular < / text >'; var reg = /<\w+>(.*?) <\/\w+>/g; console.log(str.match(reg)); / / - > ["<text>JS</text>"."< text > regular < / text >"]
Copy the code

It can be seen that the returned array contains the parent match, but does not match the child (group). Try removing the global search “g”.

var str = '< text > javascript < / text > < text > regular < / text >'; Var reg = /<\w+>(.*?) <\/\w+>/; console.log(str.match(reg)); // It will print /* ["<text>JS</text>"."JS", 
    index: 0, 
    input: 
    "< text > javascript < / text > < text > regular < / text >", 
    groups: undefined
]
*/
Copy the code

This gets the parent of the match, including the child (group), but only the first matching character. You can see that the

re
was not matched.

What if I get all of the global matches, including the children?

ES2020 provides a simple way: String. Prototype. MatchAll, this method returns an iterator.

var str = '< text > javascript < / text > < text > regular < / text >'; var allMatchs = str.matchAll(/<\w+>(.*?) <\/\w+>/g);for(const match of allMatchs) { console.log(match); } /* The first iteration returns: ["<text>JS</text>"."JS", 
    index: 0, 
    input: "< text > javascript < / text > < text > regular < / text >", groups: undefined]"< text > regular < / text >"."Regular", 
    index: 15, 
    input: "< text > javascript < / text > < text > regular < / text >", 
    groups: undefined
]
*/

Copy the code

You can see that all matches are available in each iteration, as well as some additional meta information about the success of the match.

The resources

  1. Github.com/tc39/propos…
  2. prop-tc39.now.sh/