JavaScript (JS) is a programming language that is used for dynamic scripting of web pages, usually on the client-side, but also on the server-side, via packages like Node.js.

Today, send an article about Js basic knowledge points, for more new directions. There will always be someone in front of you to explore the way for you, the road ahead, you are not alone ~

Let’s start with a directory structure

├ ─2, ├ ─ unteached, unteached, unteached, unteached, unteached, unteached, unteached, unteached, unteached, unteached, unteached, unteached, unteached How is it formed? ─ ─ ─ 4, how to understand both synchronous and asynchronous │ └ ─ ─ ─ synchronous vs asynchronous │ └ ─ ─ ─ asynchronous and single thread │ └ ─ ─ ─ the front-end asynchronous scenario description ─ ─ ─ 5, simple describe the understanding of the ES6 / ES7 │ └ ─ ─ ─ deconstruction assignment │ └ ─ ─ ─ the arrow function │ └ ─ ─ ─ Promise ├ ─ └─ Set and Map data structuresCopy the code

1. Variable declarations

1-1. Classification and judgment of JavaScript data types

In JavaScript, there are seven basic types:

  • String,
  • Number,
  • Bigint,
  • Boolean.
  • Null,
  • Undefined,
  • Symbol (new in ECMAScript 2016).

String, number, Boolean, undefined, Null and symbol are six primitive types.

It is worth noting that the primitive type does not contain Object.

What methods are used for type determination?

1, the typeof

Typeof XXX returns values of the following types: undefined Boolean Number String object Function symbol

Such as:

console.log(typeof 42);
// expected output: "number"

console.log(typeof 'blubber');
// expected output: "string"

console.log(typeof true);
// expected output: "boolean"

console.log(typeof declaredButUndefinedVariable);
// expected output: "undefined";
Copy the code

  • typeof nullAs a result,objectJavaScriptEver since we were born, becausenullRepresents a null pointer (0x00 on most platforms), so,nullThe type tag of the0.typeof nullAnd therefore return"object".
  • typeof [1, 2]As a result,objectThe result is nonearrayThis item, the reference type exceptfunctionEverything else isobject
  • typeof Symbol()typeofTo obtainsymbolThe value of type issymbolSymbolInstances are unique and immutable — this is a new wrinkle in ES6.

2, instanceof

Used for instance and constructor correspondence. For example, if a variable is an Array, use [1, 2] instanceof Array instead of typeof. Return true. Because, [1, 2] is an Array, its constructor is Array. In the same way:

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var auto = new Car('Honda'.'Accord'.1998);

console.log(auto instanceof Car);
// expected output: true

console.log([1.2] instanceof Array);
// expected output: true
Copy the code

1-2. Reference types and value types

In addition to primitive types, JS also has reference types. The above mentioned Typeof recognizes only object and function as reference types. The other types are value types.

Value type variables include Boolean, String, Number, Undefined, Null, and reference types include all Object types. Such as Date, Array, Function, etc. In terms of parameter passing, value types are passed by value and reference types are passed by share.

/ / value types
var a = 1;
var b = a;
b = 3
console.log(a) / / 1
console.log(b) / / 3
// both a and B are value types.
Copy the code
// Reference type
var a = {x: 10.y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a) // {x: 100, y: 200}
console.log(b) // {x: 100, y: 200}
Copy the code

Both a and B are reference types. After b = a, change the value of b’s attribute and change that of A. Because a and B are reference types, they refer to the same memory address, that is, they refer to the same value, so when B modifies the attribute, the value of A changes accordingly.

2. Prototype and Prototype Chain (Inheritance)

JavaScript is often described as a prototype-based language — each object has a prototype object from which the object is a template and inherits methods and properties. A stereotype object may also have a stereotype from which it inherits methods and properties, layer by layer, and so on. This relationship, often referred to as the Prototype chain, explains why one object has properties and methods defined in other objects.

Note: It is important to understand the difference between an Object’s prototype (which can be obtained via object.getProtoTypeof (obj) or the deprecated __proto__ attribute) and the constructor’s prototype attribute. The former is a property that exists on every instance, and the latter is a property of the constructor. That is, object.getProtoTypeof (new Foobar()) and foobar.prototype refer to the same Object.

In javascript, functions can have attributes. Each function has a special property called prototype, as shown below. Note that the code below is a separate piece (it is safe in the absence of other code on the page). For the best learning experience, open a Console (Ctrl+Shift+I in Chrome and Firefox), switch to the “Console” TAB, copy and paste the JavaScript code below, and press Enter to run it.

function doSomething(){}
console.log( doSomething.prototype );
// No matter how you declare functions, functions in javascript always have a default stereotype property
var doSomething = function(){}; 
console.log( doSomething.prototype );
Copy the code

As you can see above, the doSomething function has a default stereotype property, which is rendered on the console. After running this code, an object like this should appear on the console.

{
    constructor: ƒ doSomething (),__proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ `hasOwnProperty`(),
        isPrototypeOf: ƒ `isPrototypeOf`(),
        propertyIsEnumerable: ƒ `propertyIsEnumerable`(),
        toLocaleString: ƒ `toLocaleString`(),
        toString: ƒ `toString`(),
        valueOf: ƒ `valueOf`()}}Copy the code

Now we can add some properties to the doSomething prototype, as follows:

function doSomething(){}
doSomething.prototype.foo = "bar";
console.log( doSomething.prototype );
Copy the code

Output:

{
    foo: "bar".constructor: ƒ doSomething (),__proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ `hasOwnProperty`(),
        isPrototypeOf: ƒ `isPrototypeOf`(),
        propertyIsEnumerable: ƒ `propertyIsEnumerable`(),
        toLocaleString: ƒ `toLocaleString`(),
        toString: ƒ `toString`(),
        valueOf: ƒ `valueOf`()}}Copy the code

We can then use the new operator to create an instance of doSomething based on our current prototype.

function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log( doSomeInstancing );
Copy the code

Output:

{
    prop: "some value".__proto__: {
        foo: "bar".constructor: ƒ doSomething (),__proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ `hasOwnProperty`(),
            isPrototypeOf: ƒ `isPrototypeOf`(),
            propertyIsEnumerable: ƒ `propertyIsEnumerable`(),
            toLocaleString: ƒ `toLocaleString`(),
            toString: ƒ `toString`(),
            valueOf: ƒ `valueOf`()}}}Copy the code

As you can see above, doSomeInstancing’s __proto__ property is dosomething.prototype. But what good is that? Well, when you visit a property on doSomeInstancing, the browser first looks to see if doSomeInstancing has that property. If doSomeInstancing doesn’t have this property, then the browser will look for it in doSomeInstancing’s __proto__ (that is, dosome.prototype). If doSomeInstancing __proto__ has this property, then the property on doSomeInstancing __proto__ will be used. Otherwise, if doSomeInstancing’s __proto__ doesn’t have this property, the browser will go to find doSomeInstancing’s __proto__ to see if it does. By default, the __proto__ of the prototype attribute for all functions is window.object.prototype. So doSomeInstancing __proto__ (aka doSomething. Prototype’s __proto__ (aka object.prototype)) will be looked up to see if it has this property. If you don’t find the property in it, then look at doSomeInstancing in __proto__’s __proto__. There’s a problem with this, however: doSomeInstancing’s __proto__ __proto__ doesn’t exist. Finally, all __proto__ on the prototype chain is found, and the attribute is not found on all __proto__ declared by the browser, and it is concluded that the attribute is undefined.

function doSomething(){}
doSomething.prototype.foo = "bar";
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value";
console.log("doSomeInstancing.prop: " + doSomeInstancing.prop);
console.log("doSomeInstancing.foo: " + doSomeInstancing.foo);
console.log("doSomething.prop: " + doSomething.prop);
console.log("doSomething.foo: " + doSomething.foo);
console.log("doSomething.prototype.prop: " + doSomething.prototype.prop);
console.log("doSomething.prototype.foo: " + doSomething.prototype.foo);
Copy the code

Output:

doSomeInstancing.prop:      some value
doSomeInstancing.foo:       bar
doSomething.prop:           undefined
doSomething.foo:            undefined
doSomething.prototype.prop: undefined
doSomething.prototype.foo:  bar
Copy the code

It’s too much to look at. Don’t worry. Look at this:

  • All reference types (arrays, objects, functions) have object properties and can be freely extended.nullExcept)
  • For all reference types (arrays, objects, functions), there is one__proto__Property, the property value is a normal object
  • All of the functions, there’s oneprototypeProperty, the property value is also an ordinary object
  • All reference types (arrays, objects, functions),__proto__Property that points to its constructorprototypeAttribute values
// Point 1: Freely extend attributes
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;
// __proto__
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);
// The function has prototype
console.log(fn.prototype)
The __proto__ attribute value of a reference type points to the prototype attribute value of its constructor
console.log(obj.__proto__ === Object.prototype)
Copy the code

2-1. Prototype and prototype chain

The prototype

// constructor
function Foo(name, age) {
 this.name = name
}
Foo.prototype.alertName = function () {
 alert(this.name)
}
// Create an example
var f = new Foo('zhangsan')
f.printName = function () {
 console.log(this.name)
}
/ / test
f.printName()
f.alertName()
Copy the code

Well, printName makes sense, but what happens when alertName is executed? One more important thing to remember here is that when trying to get a property of an object, if the object doesn’t have the property itself, it looks in its __proto__ (its constructor’s prototype), So f.lertName will find foo.prototype.alertName.

So how do you determine if this property is a property of the object itself? The common place to use hasOwnProperty is when iterating over an object.

var item
for (item in f) {
 // Advanced browsers have already masked attributes from prototypes in for in, but it is recommended that you add this judgment to ensure normal output
 if (f.hasOwnProperty(item)) {
 console.log(item)
 }
}
Copy the code

Prototype chain

Continuing with the above example, what happens if f.tostring () is executed?

f.printName()
Copy the code

Because f itself doesn’t have toString(), and f.__proto__ (foo.prototype) doesn’t have toString. The problem comes back to the previous statement that when trying to get an attribute of an object, if the object doesn’t have the attribute itself, it will look in its __proto__ (its constructor’s prototype).

If you don’t find toString in f.proto, go to F.proto, because F.proto is a common object.

  • f.__proto__Foo.prototype, failed to findtoStringKeep looking up
  • f.__proto__.__proto__Foo.prototype.__proto__Foo.prototypeIt’s just a normal object, soFoo.prototype.__proto__isObject.prototypeIt can be found heretoString
  • sof.toStringAnd finally we get toObject.prototype.toString

If you go all the way up, you’ll find a chain, so it’s called a prototype chain. If the topmost layer is not found, it fails and returns undefined. Object.prototype.__proto__ === null The prototype chain is not infinite; the prototype chain eventually points to null.

Reference article: Simple and crude understanding of JS prototype chain – JS object-oriented programming

Please click on wechat to read the original article for a better view.

3. Scopes and closures

Scopes and closures are the most likely topics to be examined in a front-end interview

3-1. Scope

A scope is an independent domain that keeps variables from leaking and being exposed.

There are only two types of scope for variables: global variables and local variables.

Global scope:

The variables defined by the outermost function have global scope, that is, they are accessible to any inner function

var outerVar = "outer";
function fn(){
    console.log(outerVar);
}
fn(); // result:outer
Copy the code

Local scope:

In contrast to global scopes, local scopes are generally accessible only within fixed code fragments and not outside of functions, most commonly inside functions

function fn(){
    var innerVar = "inner";
}
fn();
console.log(innerVar);  // ReferenceError: innerVar is not defined
Copy the code

That’s why jQuery, Zepto, etc., all the code is placed in (function(){…. }) (). Because all variables placed inside will not be leaked and exposed, will not pollute the outside, will not affect other libraries or JS scripts. This is a representation of the scope of the function.

Note: ES6 is starting to add block-level scope, using let to define variables as follows:

if (true) {
 let name = 'Tom'
}
console.log(name) // Error because let defines name in if block-level scope
Copy the code

In this code, console.log(a) attempts to get variable A, but no a is defined in the current scope, and looks up level by level until it finds the global scope. This layer by layer relationship is the scope chain.

var a = 5
function fn() {
 var b = 10
 console.log(a)
 console.log(b)
}
fn()
Copy the code

3-2 What is a closure and how is it formed

So what is a closure? There are many opinions, and the most frequent ones are the following two:

  • Functions cover functions.
  • The technique of obtaining variables from outside a function.
function F1() {
 var a = 100
 return function () {
 console.log(a)
 }
}
var f1 = F1()
var a = 200
f1()
Copy the code

Closures have two main applications:

  • Function as the return value, as in the example above
  • Functions are passed as arguments, as shown in the following example
function F1() {
 var a = 100
 return function () {
 console.log(a)
 }
}
function F2(f1) {
 var a = 200
 console.log(f1())
}
var f1 = F1()
F2(f1)
Copy the code

About this object

var name = "The Window";
var object = {
    name : "My Object".getNameFunc : function(){
        return function(){
            return this.name; }; }}; alert(object.getNameFunc()());// result:The Window
Copy the code

The this object is bound at runtime based on the function’s execution environment: in a global function, this equals window, and when the function is called as an object, this equals that object. However, anonymous functions are global, so this object will always point to window.

4. How to understand synchronous and asynchronous

4-1. Synchronous vs asynchronous

First print 100, then print 200 after 1 second, then print 300. But the actual operation is nothing like that.

console.log(100)
setTimeout(function () {
 console.log(200)},1000)
console.log(300)
Copy the code

Compare the following program. Print 100, pop up 200 (for user confirmation), and print 300. This operation results in the desired requirements.

console.log(100)
alert(200) // After 1 second, click Ok
console.log(300)
Copy the code

What’s the difference between these two? The middle step in the first example does not block subsequent programs at all, while the second example does. This behavior is called asynchronous (the latter is called synchronous) and does not block subsequent programs.

4-2, Asynchronous and single-threaded

setTimeout(function(){
 a = false;
}, 100)
while(a){
 console.log('While executes')}Copy the code

Since JS is single-threaded and can only do one thing at a time, after entering the while loop, there is no “time” (thread) to run the timer, so the code runs in an infinite loop!

4-3 Front-end asynchronous scenario description

  • Scheduled task:setTimeout.setInterval
  • Bind events:addEventListener(clickEtc.)
  • Network request:ajaxandimgDynamic loading

5, briefly describe the understanding of ES6/ES7

5-1. Deconstruct assignment

ES6 allows you to extract values from arrays and objects and assign values to variables in a pattern called Destructuring.

Previously, to assign a value to a variable, you had to specify a value directly.

let a = 1;
let b = 2;
let c = 3;
Copy the code

ES6 allows you to write it like this.

let [a, b, c] = [1.2.3];
Copy the code

The assignment code is greatly reduced. There is no need to declare the definition and assignment of variables a,b, and c respectively, just take variables a,b, and c as elements of an array, and then assign the array [1,2,3] to the array [a,b,c]. Variables a,b, and c can get the corresponding values respectively.

1. Structure assignments can be nested

let [ a,b,[ c1,c2 ] ] = [ 1.2[3.1.3.2]].console.log(c1);// c1 has a value of 3.1
console.log(c2);// c2 has a value of 3.2
Copy the code

2. Incomplete deconstruction

let [a, b, c] = [1.2];
console.log(a);// the value of a is 1
console.log(b);// the value of b is 2
Copy the code

3. The value of the variable is equal to undefined if the deconstruction fails.

let [a,b,c] = [1.2];
console.log(a);// the value of a is 1
console.log(b);// the value of b is 2
console.log(c);// Result: c is undefined
Copy the code

4. Destruct assignment allows specifying default values

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a'.undefined]; // x='a', y='b'
Copy the code

Note that ES6 internally uses the strict equality operator (===) to determine whether a position has a value. Therefore, the default value is valid only if an array member is strictly equal to undefined.

Object destructuring assignment

var { a,b,c } = {"a":1."c":3."b":2};
    console.log(a);// Result: A = 1
    console.log(b);// result: b is 2
    console.log(c);// Result: c = 3
Copy the code

Destruct assignment of a string

var [a,b,c,d,e,f] = "I am a bird.";
    console.log(a);/ / I
    console.log(b);/ / is
    console.log(c);/ / a
    console.log(d);/ / only
    console.log(e);/ / small
    console.log(f);/ / bird
Copy the code

Deconstruct the purpose of assignment

Swap values of variables

    var x = 1;
    var y = 2;
    [x,y] = [y,x];
Copy the code

Extract multiple values returned by the function

function demo(){
    return {"name": "Zhang"."age": 21}}var {name,age} = demo();
console.log(name);// Result: Zhang SAN
console.log(age);// Result: 21
Copy the code

Define function parameters

function demo({a,b,c}){
    console.log("Name:"+ a);
    console.log("Height:"+ b);
    console.log("Weight:"+ c);
}
demo({a:"Tang three".b:"1.72 m".c:"50kg".d:"8000"});
/* It is very easy to extract the desired parameters from the JSON object. For example, in our case, we only need to get the parameters a, b, and c, and do not need other parameters, such as d or more. * /
Copy the code

Extract JSON data

let jsonData = {
  id: 42.status: "OK".data: [867.5309]};let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]
Copy the code

Fifth, the input module of the specified method

When a module is loaded, it is often necessary to specify which methods to input. Deconstructing assignment makes the input statement very clear.

const { SourceMapConsumer, SourceNode } = require("source-map");
Copy the code

5-2. Grammar of Module

Historically, JavaScript has not had a module system that allows you to break up a large program into small interdependent files and put them together in a simple way. Other languages have this functionality, such as Ruby’s require, Python’s import, and even CSS has @import, but JavaScript has no support for any of this, which is a huge barrier to developing large, complex projects.

/ / CommonJS module
let { stat, exists, readFile } = require('fs');

/ / is equivalent to
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
Copy the code

The above code essentially loads the FS module as a whole (that is, all the methods that load FS), generates an object (_fs), and then reads three methods from that object. This type of loading is called “runtime loading” because the object is only available at runtime, making it completely impossible to do “static optimization” at compile time.

Export: As a module, it can optionally expose (provide) its own properties and methods to other modules for use by other modules.

Import Import: A module can Import properties or methods provided by other modules as needed for its own module to use.

Modular implementation

/ / module - - B.j s file

// Export variable name
export var name = "Modular"; 
Copy the code

Module B uses the keyword export to expose an attribute: the value of name is the string “modular”. A key word, a code to achieve, is not very simple.

/ / module - - a. s file

// Import the attribute name of module B
import { name } from "./module-B.js";
console.log(name)
// Prints the result: modularization
Copy the code

Module A imports the name attribute of module B using the keyword import and assigns the value to the variable name. The keyword from is used to specify which module you want to import. In this case, we specify module-b.js file, which is module B above. “Modularity” is the exposed property of module B.

5-3. Arrow functions

This in the arrow function refers to this at definition, not this at execution.

// Define an object
var obj = {
    x:100./ / property x
    show(){
        // Delay 500 ms, output x value
        setTimeout(
        // Difference: arrow function() = > {console.log(this.x)},
        500); }}; obj.show();// Print the result: 100
Copy the code

When we define the show() method of obj, we write this.x in the arrow function, where this refers to obj, so this.x refers to obj.x. When show() is called, this still refers to the object to which it was defined, which is obj, so it prints: 100.

5-4. Promise objects

Promise is a solution to asynchronous programming that makes more sense and is more powerful than traditional solutions — callback functions and events. It was first proposed and implemented by the community, and ES6 has written it into the language standard, unifying usage, and providing Promise objects natively.

ES6 specifies that a Promise object is a constructor that generates a Promise instance.

Promise objects have three states:

  • pending: indicates the initial state when a Promise instance is created;
  • fulfilledIf the: resolve method is invoked, the operation succeeds.
  • rejectedWhen the: reject method is invoked, the operation fails.

This state can only be reversed from the initialization -> success or the initialization -> failure, and can not be reversed between the success pity and the failure rejected.

const pro = new Promise(function(resolve, reject) {
  // ... some code

  if (/* Asynchronous operation succeeded */){
    resolve(value);
  } else{ reject(error); }});Copy the code

With Promise creation and state in mind, let’s look at one of the most important instance methods: the then() method.

pro.then(function (res) {
    // The handler that operated successfully
},function (error) {
    // The handler for the failed operation
});
// Arguments are two functions, the first for the successful operation and the second for the abnormal operation.
Copy the code

The catch () method

pro.catch(function (error) {
    // The handler for the failed operation
});
Copy the code

Chained invocation is possible because both the then and catch methods, when called, return a Promise object.

If you haven’t heard of Promise before, you’re probably confused right now. That’s okay. Let’s use an example to connect the dots.

// Create a Promise instance with the new keyword
    let pro = new Promise(function(resolve,reject){
        // Assume condition is true
        let condition = true;

        if(condition){
            // Call the operation success method
            resolve('Operation successful');
            // State: pending-> depressing
        }else{
            // Call the operation exception method
            reject('Operation exception');
            // Status: Pending -> Rejected}});// Use then to process the operation successfully, catch to process the operation exception
    pro.then(function (res) {

        // The handler that operated successfully
        console.log(res)

    }).catch(function (error) {

        // The handler for the failed operation
        console.log(error)

    });
    // Console output: Operation successful
Copy the code

The comments for the case above are very detailed, connecting all of the points mentioned above: instance creation, state transitions, and the use of then and catch methods.

Since we set the value of condition to true, the console output after execution is: “Operation succeeded.”

This is the process that Promise uses to handle operation exceptions; But, as we discussed at the beginning of this article, what if there are layers of dependencies between multiple operations?


    let pro = new Promise(function(resolve,reject){

        if(true) {// Call the operation success method
            resolve('Operation successful');
        }else{
            // Call the operation exception method
            reject('Operation exception'); }});// Use then to process the operation successfully, catch to process the operation exception
    pro.then(requestA)
        .then(requestB)
        .then(requestC)
        .catch(requestError);

    function requestA(){
        console.log('Request A successful');
        return "Request B, you're next.";
    }
    function requestB(res){
        console.log('Result of previous step:'+res);
        console.log('Request B successful');
        return "Request C, you're next.";
    }
    function requestC(res){
        console.log('Result of previous step:'+res);
        console.log('Request C successful');
    }
    function requestError(){
        console.log('Request failed');
    }

    // Print the result:
    // Request A succeeded
    // The result of the previous step: request B, you are next
    // Request B succeeds
    // The result of the previous step: request C, you are next
    // Request C succeeds
Copy the code

In this case, we create an instance and declare four functions, three of which represent request A, request B, and request C. With the THEN method, three request operations no longer need to be nested in layers. We use the then method to bind the three operations in the order in which they are called. Moreover, if request B depends on the result of request A, we can use the return statement to pass the required data as parameters to the next request. In this case, we use the return implementation to pass parameters to the next operation.

A more intuitive diagram

Promise. All () method

Promise.all() method: Accepts an array as parameter, the elements of which are Promise instance objects. When the state of the instance objects in the parameter is fulfilled, promise.all () will return.

// Create instance pro1
    let pro1 = new Promise(function(resolve){
        setTimeout(function () {
            resolve('Instance 1 operation succeeded');
        },5000);
    });
    
    // Create instance pro2
    let pro2 = new Promise(function(resolve){
        setTimeout(function () {
            resolve('Instance 2 operation succeeded');
        },1000);
    });

    
    Promise.all([pro1,pro2]).then(function(result){
        console.log(result);
    });
    // Print result: [" Operation succeeded in instance 1 ", "operation succeeded in Instance 2 "]
Copy the code

Promise. Race () method

Another similar method is the promise.race () method: This parameter requirement is the same as the promise.all () method. The difference is that as long as one of the Promise instances in this parameter changes (whether this is a successful pity or an exception rejected), it will return.

// Initialize instance pro1
    let pro1 = new Promise(function(resolve){
        setTimeout(function () {
            resolve('Instance 1 operation succeeded');
        },4000);
    });

    // Initialize instance pro2
    let pro2 = new Promise(function(resolve,reject){
        setTimeout(function () {
            reject('Instance 2 operation failed');
        },2000);
    });

    Promise.race([pro2,pro1]).then(function(result){
        console.log(result);
    }).catch(function(error){
        console.log(error);
    });
    // Result: The operation in example 2 fails
Copy the code

We have two instances, same instance pro1, different instance pro2, and this time we call reject.

Because the reject method is executed after 2000 ms in pro2, which is earlier than the 4000 ms in Pro1, the final output reads: Instance 2 failed.

That’s all I have to say about Promise objects, including the concept of callback hell; It refers to the excessive use of nested callback functions, which makes debugging and maintenance extremely inconvenient.

Reference: MDN

How do YOU use ES6 Promise objects