Implement according to the Promise A+ specification, with additional static methods such as all, RACE, etc.

The implementation of the code conforms perfectly to the Promise A+ specification

Promise/A+ specification

Specifications are the specifications (or you don’t have to follow…) that we use to implement promises. .

Well, I’m too tired to write the specification, but promise A+ can be found below:

  • [Promise A+ specification – 英 文](Promise A+ Specification (MalcolmyU.github. IO)
  • [Promise A+ specification – 英 文](Promise/A+ specification – SegmentFault)
  • Promise A+ Specification – English

Our main task is still based on code implementation!

The basic structure

With a native Promise, we know that a Promise is actually a constructor. After all, only a constructor can use new, so we implement our code in ES6 syntax.

First, let’s build the skeleton of our Promise class

class Promise {
    constructor(){}}Copy the code

actuator

A Promise takes a parameter, which is a function, and it contains two parameters, resolve and reject.

So, we need to receive this function in the constructor.

As long as you’re not too rudimentary, you can see that resolve and Reject are passed by our class, which means that they are the methods on the Promise itself

class Promise {
	constructor(executor) {
        executor(this.resolve, this.reject);
    }
    
    resolve = () = > {}
    
    reject = () = >{}}Copy the code

Here, we did a few things:

  1. Receive the executor function
  2. Add the resolve and reject methods to the class
  3. Execute the executor and pass our resolve and reject to it

To realize the resolve

Any of you who have used a native promise should know that resolve is a function that takes one argument. Here is an example of a native Promise

/ / the original Promise
new Promise((resolve, reject) = > {
    resolve(1); // This is what we want to achieve
}).then(value= > {
    console.log(value); // Select 'value' from 'then' where 'value' is' 1 '
});
Copy the code

Let’s implement resolve. Before we implement resolve, we know:

This is very depressing. This is very depressing. This is very depressing.

This is very depressing. Once a promise is resolved, it will change its state from pending to fulfilled.

And also, your argument 1 in resolve(1) is something I have to accept, right? We’ll just receive it with a variable value. The resolve parameter is optional. You can pass it. If you pass it, I will accept it. If you do not pass it, I will default to undefined.

Finally, the effect of resolve is to change a promise from the pending state to the fulfilled state.

const PENDING = 'pending'; // pending Wait state
const FULFILLED = 'fulfilled'; // Resolve Indicates the successful state
const REJECTED = 'rejected'; // reject Failed state

class Promise {
    state = PENDING; // The initial state of the promise is pending by default
	value = null; / / the value of the resolve
    
	constructor(executor) {
        executor(this.resolve, this.reject);
    }
    
    resolve = (value) = > {
        // Resolve is valid only when the status is pending
        if(this.state === PENDING) {
            This is fulfilled
            this.state = FULFILLED;
            this.value = value; }}}Copy the code

Realize the reject

Reject is implemented in a similar way to resolve, except that it changes the promise state from pending to Rejected.

Similarly, Reject can take an argument, so we use a variable called Reason to hold the argument.

const PENDING = 'pending'; // pending Wait state
const FULFILLED = 'fulfilled'; // Resolve Indicates the successful state
const REJECTED = 'rejected'; // reject Failed state

class Promise {
    state = PENDING; // The initial state of the promise is pending by default
	value = null; / / the value of the resolve
	reason = null; / / reject reason
    
	constructor(executor) {
        executor(this.resolve, this.reject);
    }
    
    reject = (reason) = > {
        // Resolve is valid only when the status is pending
        if(this.state === PENDING) {
            This is fulfilled
            this.state = FULFILLED;
            this.reason = reason; }}}Copy the code

test

At this point, let’s do a little test to see if our code is wrong.

new Promise((resolve, reject) = > {
    console.log('Execute our own promise');
})
Copy the code

If the above code outputs the contents of console properly, then this is correct.

So let’s keep going.

Implement then (key difficulty)

Before implementing, we should know a few points:

  1. When will then be triggered
  2. How many parameters does “then” have
  3. What if then has a return value

Let’s answer the three questions above first

/ / the original Promise
new Promise((resolve, reject) = > {
    console.log(1);
    resolve(2);
}).then(value= > {
    console.log(value);
    return 3;
}, err= > {
    console.log(err);
}).then(value= > {
    console.log(value);
})
Copy the code

Looking at the code above, we know that

  1. A then is triggered only if the Promise is instantiated at the same time that the resolve is executed
  2. This parameter will be fulfilled someday and this parameter will be rejected. This parameter will be fulfilled someday and this parameter will be fulfilled someday
  3. The return value from the then is used as an argument to the next callback to the then success state

Finally, we need to know that the A+ specification specifies that the names of the two parameters to then should be:

  • OnFulfilled: promise When the state is successful, the parameter is value or none.
  • OnRejected: Promise If the state is failed, the parameter is reason or none.

The basic form

The then method is essentially a method on our Promise class that takes two parameters, and that’s it.

class Promise {
	/ *... . * /
    
    then = (onFulfilled, onReject) = >{}}Copy the code

onFulfilled

This is very depressing. This is the function that is called when our promise’s current state is success.

It takes a parameter value, which is our value in resolve(value).

// This will be fulfilled
then = (onFulfilled, onReject) = > {
    This is fulfilled only when the current state is successful fulfilled
    if(this.state === FULFILLED) {
        // Perform onFulfilled and pass our value to it
        onFulfilled(this.value); }}Copy the code

onReject

OnFulfilled is similar to onFulfilled, except that it is only called when our promise is in a failed state.

It takes one argument, which is reject(Reason).

// The onReject implementation in then
then = (onFulfilled, onReject) = > {
    // Execute only if the current status is Successfully rejected
    if(this.state === REJECTED) {
        // Execute onReject and pass our reason to it
        onReject(this.reason); }}Copy the code

test

So, let’s test a wave

// Our promise
new Promise((resolve, reject) = > {
    console.log('value'.1);
    resolve(2);
}).then(value= > {
    console.log('value', value);
});

// Execution result
// value 1
// value 2
Copy the code

When you look at the execution, you can see that our code is perfectly implemented.

But what if our promise involves asynchronous operations?

// Our promise
new Promise((resolve, reject) = > {
    console.log('value'.1);
    // Simulate asynchronous code, assuming we are sending an Ajax request
    setTimeout(() = > {
        resolve(2);
    }, 0);
}).then(value= > {
    console.log('value', value);
});

// Execution result
// value 1
Copy the code

According to! Why is that? Where is our value 1?

The thing is, our setTimeout is asynchronous code, so it’s going to be delayed, even if it takes you zero time to write.

Then, after throwing your asynchronous code away to play in the mud, js looks back to see if there is any more code, and it finds “then”.

Since our then is synchronous code at the moment, it executes the THEN first, and then executes our setTimeout when the then is done.

Do you think it’s important for you to resolve?

Asynchronous processing

Resolve: Resolve: Resolve: Resolve: Resolve: Resolve: Resolve: Resolve: Resolve

First, we know that the initial state of a promise is pending, and only resolve and Reject can modify the state.

}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}

class Promise {
    / /...
    onFulfilledCallback = null; // The function to execute on success
	onRejectedCallback = null; // The function to execute on failure

    // This will be fulfilled
    then = (onFulfilled, onReject) = > {
        // Execute only when the current state is successfully pending
        if(this.state === PENDING) {
            // Save the handler when successful
            this.onFulfilledCallback = onFulfilled;
            // Save the failure handler
            this.onRejectedCallback = onReject; }}}Copy the code

The pending state is added to the THEN, and two class attributes are added.

Next, we have to do one more thing, we work to save the success and failure handler, so when and where to call?

The answer is: resolve and reject

resolve = () = > {
    resolve = (value) = > {
        // Resolve is valid only when the status is pending
        if (this.state === PENDING) {
            / /...
            // Call resolve to change the status of the successful handler to successful
            this.onFulfilledCallback && this.onFulfilledCallback(value);
        }
    }

    reject = (reason) = > {
        // Resolve is valid only when the status is pending
        if (this.state === PENDING) {
            / /...
            // Reject is called. The reject handler is executed when the modification state is failed
            this.onRejectedCallback && this.onRejectedCallback(reason); }}}Copy the code

test

Test the asynchronous code again

// Our promise
new Promise((resolve, reject) = > {
    console.log('value'.1);
    // Simulate asynchronous code, assuming we are sending an Ajax request
    setTimeout(() = > {
        resolve(2);
    }, 1500);
}).then(value= > {
    console.log('value', value);
});

// Execution result
// value 1
// value 2
Copy the code

As you can see, our timer is set for 1.5 seconds, and when output value 1, we wait 1.5 seconds, and then output value 2.

So, our asynchronous processing is done.

At this point, our code has already started to get complicated, but it’s not a problem, if you feel a little dizzy, don’t read down, first to clarify the above knowledge, write and think a few times will be.

Chain calls

Let’s start with the native promise chained call example

new Promise((resolve, reject) = > {
    resolve(1);
}).then().then().then().then().....
Copy the code

And as you can see, you can go down to then indefinitely.

And ours turned out to be…

// Our promise
new Promise((resolve, reject) = > resolve(1))
    .then(value= > {
        console.log('value', value);
    })
    .then(value= > { // Error: 'then' is undefined
        console.log('value', value);
    });

// TypeError: Cannot read property 'then' of undefined
Copy the code

Before we do this requirement, let’s think about the question, what can we use then?

** ANSWER: **Promise instance object

Since then is a method of the Promise class, only instances of the Promise have then

So, how do we do a chained call then?

** Then returns an instance object of the Promise each time it is called.

So let’s do that

then = (onFulfilled, onReject) = > {
	// Put all of our previous code into this promise2
    let promise2 = new Promise((resolve, reject) = > {
        This is fulfilled only when the current state is successful fulfilled
        if (this.state === FULFILLED) {
            // Perform onFulfilled and pass our value to it
            onFulfilled(this.value);
        }

        // Execute only if the current status is Successfully rejected
        if (this.state === REJECTED) {
            // Execute onReject and pass our reason to it
            onReject(this.reason);
        }

        // Execute only when the current state is successfully pending
        if (this.state === PENDING) {
            // Save the handler when successful
            this.onFulfilledCallback = onFulfilled;
            // Save the failure handler
            this.onRejectedCallback = onReject; }});// Return the promise2 instance
    return promise2;
}
Copy the code

If I run the previous round of tests again, I will find that my second “THEN” seems not to have been executed.

Let’s change the code:

class Promise {
    / /...
    onFulfilledCallback = []; // The function to execute on success
    onRejectedCallback = []; // The function to execute on failure

    // ...

    resolve = (value) = > {
        // Resolve is valid only when the status is pending
        if (this.state === PENDING) {
            / /...
            // Call resolve to change the status of the successful handler to successful
            while (this.onFulfilledCallback.length) {
                this.onFulfilledCallback.shift()();
            }
        }
    }

    reject = (reason) = > {
        // Resolve is valid only when the status is pending
        if (this.state === PENDING) {
            / /...
            // Reject is called. The reject handler is executed when the modification state is failed
            while (this.onRejectedCallback.length) {
                this.onRejectedCallback.shift()(); }}}// This will be fulfilled
    then = (onFulfilled, onReject) = > {
        // Return a Promise instance to implement the chained call function
        let promise2 = new Promise((resolve, reject) = > {
            // The successful handler
            const onFulfilledCallback = () = > {
                // Perform onFulfilled and pass our value to it
                setTimeout(() = > {
                    // Get the return value of resolve or reject and assign it to the variable x
                    const x = onFulfilled(this.value);
                    // Perform different operations depending on the type of return value
                    this.resolvePromise(promise2, x, resolve, reject); })}// Failure handler
            const onRejectedCallback = () = > {
                // Execute onReject and pass our reason to it
                setTimeout(() = > {
                    // Get the return value of resolve or reject and assign it to the variable x
                    const x = onReject(this.reason);
                    // Perform different operations depending on the type of return value
                    this.resolvePromise(promise2, x, resolve, reject); })}This is fulfilled only when the current state is successful fulfilled
            if (this.state === FULFILLED) {
                // Execute the success handler
                onFulfilledCallback();
            }

            // Execute only if the current status is Successfully rejected
            if (this.state === REJECTED) {
                // Execute the failure handler
                onRejectedCallback();
            }

            // Execute only when the current state is successfully pending
            if (this.state === PENDING) {
                // Save the handler when successful
                this.onFulfilledCallback.push(onFulfilledCallback);
                // Save the failure handler
                this.onRejectedCallback.push(onRejectedCallback); }});return promise2;
    }

    // Process the return value of the then
    resolvePromise = (promise2, x, resolve, reject) = > {
        if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {}else{ resolve(x); }}}Copy the code

So, what did we do with this whole bunch of code?

  1. Change the variables that hold the success and failure state handlers to arrays
  2. Resolve and Reject both loop through our array of state handlers at the end, fetching and executing in turn.
  3. Encapsulate the success handler and failure handler separately and put them into a timer for execution.
  4. Added the **resolvePromise * class method

Why are you doing this?

Every time we click “THEN”, the “THEN” function is executed, and the “then” success and failure handlers are also handled.

promise.then().then().then().then().then()...
Copy the code

This code fires the THEN method five times

Also, the return value of the previous THEN

Is the resolve argument to the next then

We also said that only if the PROMISE calls resolve can we enter then

If we return a promise2?

If you return a PROMISE instance object, can I go to the next one if you don’t call resolve?

Can’t!

So how do you tell if “then” returns a value? This is very depressing. OnFulfilled and onRejected are the two methods of then. I can accept this with an x variable.

After receiving the return value of then (undefined if there is no active return)

I added a new class method, resolvePromise, to determine whether to call resolve or reject at the end of the then.

In the resolvePromise, according to the Promise A+ specification, we need to perform different operations based on the data type of X.

resolve = (promise2, x, resolve, reject) = > {
    // If x is an object or function
    if(x ! = =null && (typeof x === 'object' || typeof x === 'function'))) {}else {
        // In this case, x is a normal value type. Use resolve to take x awayresolve(x); }}Copy the code

So why did I write it in the timer?

This is very depressing. This variable will be fulfilled someday, which will be fulfilled someday. This variable will be fulfilled someday, which will be fulfilled someday.

then = (onFulfilled, onReject) = > {
    let promise2 = new Promise((resolve, reject) = > {
        if(this.state === FULFILLED) {
            // Get the return value of resolve or reject
            const x = onFulfilled(this.value);
            // Perform different operations depending on the type of return value
            this.resolvePromise(promise2, x, resolve, reject);
            // TypeError indicates that promise2 is not initialized before use...}});return promise2;
}
Copy the code

If we don’t use a timer to delay the execution of promsie2, we can’t get the promsie2, because promisE2 hasn’t been initialized yet and it doesn’t exist, so we need to use a timer.

At this point, our Promise chain call function is complete.

Or that sentence, this section is a little difficult, also a little around, if there is no understanding, the proposal first this piece of content clear!

Perfect resolvePromise

The resolvePromise function is used to handle the return value from then. What if your return value is a normal value, object or function?

We need to follow the Promise A+ specification to implement!

Take a look at our current code

resolvePromise = (promise2, x, resolve, reject) = > {
    // If x is an object or function
    if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {}else {
        // Can enter here, which means x is a common valueresolve(x); }}Copy the code

According to the A+ specification, if x is an object or function, declare A variable then and assign X. Tet to it. Reject the error if x does not have the THEN attribute

resolvePromise = (promise2, x, resolve, reject) = > {
    // If x is an object or function
    if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
        // Declare a variable then
        let then;
		try {
            If x is set to unreadable, try/catch is required. If x is set to unreadable, try/catch is required.
            then = x.then;
        } catch (err) {
            // Rejectreject(err); }}else {
        // Can enter here, which means x is a common valueresolve(x); }}Copy the code

Next, we need to determine whether the variable then is a function

If then is a function, then

  1. Change this of then to point to x
  2. Pass two parameters (which are actually the two parameters to the then method)
    1. y: the resolve method equivalent to then executes the resolvePromise when called
    2. r: Reject method equivalent to then
    3. ifyrAre called, or are called multiple times, only the first time is valid, and the rest is ignored.
    4. If you callthenWhen an exception is thrown, then:
      1. ifyrIf it has already been called, ignore it.
      2. Otherwise, in order toeFor a tinypromiseTo refuse.

If then is not a function, then

  1. With the value x, call resolve

Code implementation

// If x is an object or function
if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
    // Declare a variable then
    let then;
    // Declare a variable called to indicate whether y or r has been called
    let called = false; // False means that it has not been called
    try {
        If x is set to unreadable, try/catch is required. If x is set to unreadable, try/catch is required.
        then = x.then;
    } catch (err) {
        // Reject
        reject(err);
    }

    // Determine if then is a function
    if (typeof then === 'function') {
        try {
            // Change this to point to x
            then.call(
                x,
                y= > {
                    // Exit if y or x has already been called
                    if (called) return;
                    // Change called to called
                    called = true;
                    // Execute the resolvePromise again
                    this.resolvePromise(promise2, y, resolve, reject);
                },
                r= > {
                    // Exit if y or x has already been called
                    if (called) return;
                    // Change called to called
                    called = true;
                    // reject the rreject(r); })}catch (e) {
            // If then makes an error while being called, then it goes in here, reject directlyreject(e); }}else {
        // Resolve with x if then is not a functionresolve(x); }}else {
    // Resolve with x if x is not an object or function
    resolve(x);
}
Copy the code

At this point, our resolvePromise method is complete

Exception handling

In order to avoid errors during code execution that can crash the program, we need to tolerate errors where they might occur

** Success handlers add try/catch **

// The successful handler
const onFulfilledCallback = () = > {
    // Perform onFulfilled and pass our value to it
    setTimeout(() = > {
        try {
            // Get the return value of resolve
            const x = onFulfilled(this.value);
            // Perform different operations depending on the type of return value
            this.resolvePromise(promise2, x, resolve, reject);
        } catch(error) { reject(error); }})}Copy the code

Failure handlers add try/catch functions

// Failure handler
const onRejectedCallback = () = > {
    // Execute onReject and pass our reason to it
    setTimeout(() = > {
        try {
            // Get the reject return value
            const x = onReject(this.reason);
            // Perform different operations depending on the type of return value
            this.resolvePromise(promise2, x, resolve, reject);
        } catch(error) { reject(error); }})}Copy the code

Add catch method

There is a catch method in a native Promise instance object, which is usually written at the end of a chained call

new Promise((resolve, reject) = > {
    resolve(1);
})
.then(value= > {
    return Promise.reject('This is an error message.');
})
.catch(err= > {
    console.log('err', err);
})
Copy the code

If the error is not caught in the then, then the error message will be caught by the final catch.

So let’s do that, and the implementation code is pretty simple

catch = (onRejected) = > {
    Reject (reject); reject (Reject); reject (Reject)
    return this.then(null, onRejected);
}
Copy the code

other

The two arguments to the THEN method are optional and may or may not be passed.

Let’s also make them optional.

Note: Follow the PROMISE A+ specification

then = (onFulfilled, onRejected) = > {
    If onFulfilled is not a function, give it a default function
    if (typeofonFulfilled ! = ='function') onFulfilled = value= > value;
    // If onRejected is not a function, give it a default function that throws a reason error message
    if (typeofonRejected ! = ='function') onRejected = reason= > { throw reason };
}
Copy the code

Do not understand why the same child, need to see more times, more analysis several times

At this point, our promise has been fulfilled

As you can see, the THEN method is the most complex of the promise implementations

But actually, if you watch it a few times, you’ll find it’s not that hard


Implementing static resolve

Let’s look at the example of a native promise

new Promise((resolve, reject) = > {
    resolve(1);
}).then(value= > {
    return Promise.resolve(2);
}).then(value= > {
    console.log(value); / / 2
})
Copy the code

As you can see in the example above, resolve is a static method that returns a promise with a successful state, so we can continue to point back to then.

So, let’s do it, and the implementation is pretty straightforward.

static resolve = (value) = > {
    return new Promise((resolve, reject) = >{ resolve(value); })}Copy the code

Yes, you read that right. It’s that simple.

It receives the parameter passed by the user, creates a PROMISE object, and calls the resolve(value) of the instance object to exit, perfect!

Implementing static Reject

Since there is static resolve, there is also static reject.

The implementation process is almost the same as static resolve.

static reject = (reason) = > {
    return new Promise((resolve, reject) = >{ reject(reason); })}Copy the code

Implementing static ALL

Let’s look at a primitive example

letpromises = [...] ;Promise
	.all(promises)
    .then(value= > {
        console.log(value);
    })
Copy the code

If you don’t know promise. all, please go to Baidu. I won’t go into details here.

The promise.all method is often used to implement concurrency, such as concurrent requests.

At the same time, its characteristics are: all promise state is successful, is a success, as long as one promise is failed, all fail.

So let’s do that

static all = (promises) = > {
    let result = [];
    let count = 0;
    
    // Check whether the parameter is an array. If it is not an array, the parameter is returned without execution
    if (!Array.isArray(promises)) return promises;
    
    return new Promise((resolve, reject) = > {
        // Add data to result
        const insertData = (data, index) = > {
            result[index] = data;
            count++;
            // Check whether the execution is complete
            if(count === result.length) { resolve(result); }}// Use a loop to iterate over all promises and execute
        for(let i = 0; i < promises.length; i++) {
            promises[i].then(value= >insertData(value, i), reject); }})}Copy the code

Implementing static RACE

Race is similar to all, with the following differences:

As long as one promise is successful, the whole is the whole, and only when all promises are failures is a failure.

The implementation code

static race = (promises) = > {
    if (!Array.isArray(promises)) return promises;
    return new Promise((resolve, reject) = > {
        for(let i = 0; i < promises.length; i++) { promises[i].then(resolve, reject); }})}Copy the code

A+ specification test

All of our promises have been implemented, so let’s test whether our code conforms to the Promise A+ specification

To test the code, we need to add a static method to our Promise class (which is only used for testing and can be removed after testing).

// Copy all of them and don't change anything
static deferred = function () {
    let result = {};
    result.promise = new Promise(function (resolve, reject) {
        result.resolve = resolve;
        result.reject = reject;
    });

    return result;
}
Copy the code

Next, export the Promise class we wrote (commonJS specification)

module.exports = Promise;
Copy the code

Finally, to execute the test, open the command line tool in the same directory as our file and type the following command

npx promises-aplus-tests .\xxx.js
Copy the code

Where xxx.js is your file name, it’s the Promise file we wrote

I tested it, and all the code passed the test. Comfortable


The complete code

const PENDING = 'pending'; // pending Wait state
const FULFILLED = 'fulfilled'; // Resolve Indicates the successful state
const REJECTED = 'rejected'; // reject Failed state

class Promise {
    state = PENDING; // The initial state of the promise is pending by default
    value = null; / / the value of the resolve
    reason = null; / / reject reason
    onFulfilledCallback = []; // The function to execute on success
    onRejectedCallback = []; // The function to execute on failure

    constructor(executor) {
        executor(this.resolve, this.reject);
    }

    resolve = (value) = > {
        // Resolve is valid only when the status is pending
        if (this.state === PENDING) {
            This is fulfilled
            this.state = FULFILLED;
            this.value = value;
            // Call resolve to change the status of the successful handler to successful
            while (this.onFulfilledCallback.length) {
                this.onFulfilledCallback.shift()();
            }
        }
    }

    reject = (reason) = > {
        // Resolve is valid only when the status is pending
        if (this.state === PENDING) {
            // Change the status to Rejected
            this.state = REJECTED;
            this.reason = reason;
            // Reject is called. The reject handler is executed when the modification state is failed
            while (this.onRejectedCallback.length) {
                this.onRejectedCallback.shift()();
            }
        }
    }

    then = (onFulfilled, onRejected) = > {
        If onFulfilled is not a function, give it a default function
        if (typeofonFulfilled ! = ='function') onFulfilled = value= > value;
        // If onRejected is not a function, give it a default function that throws a reason error message
        if (typeofonRejected ! = ='function') onRejected = reason= > { throw reason };

        let promise2 = new Promise((resolve, reject) = > {
            // The successful handler
            const onFulfilledCallback = () = > {
                // Perform onFulfilled and pass our value to it
                setTimeout(() = > {
                    try {
                        // Get the return value of resolve
                        const x = onFulfilled(this.value);
                        // Perform different operations depending on the type of return value
                        this.resolvePromise(promise2, x, resolve, reject);
                    } catch(error) { reject(error); }})}// Failure handler
            const onRejectedCallback = () = > {
                // Execute onRejected and pass our reason to it
                setTimeout(() = > {
                    try {
                        // Get the reject return value
                        const x = onRejected(this.reason);
                        // Perform different operations depending on the type of return value
                        this.resolvePromise(promise2, x, resolve, reject);
                    } catch(error) { reject(error); }})}This is fulfilled only when the current state is successful fulfilled
            if (this.state === FULFILLED) {
                onFulfilledCallback();
            }

            // Execute only if the current status is Successfully rejected
            if (this.state === REJECTED) {
                onRejectedCallback();
            }

            // Execute only when the current state is successfully pending
            if (this.state === PENDING) {
                // Save the handler when successful
                this.onFulfilledCallback.push(onFulfilledCallback);
                // Save the failure handler
                this.onRejectedCallback.push(onRejectedCallback); }});return promise2;
    }

    resolvePromise = (promise2, x, resolve, reject) = > {
        if (promise2 === x) reject(new TypeError('Circular reference error'));
        // If x is an object or function
        if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
            // Declare a variable then
            let then;
            // Declare a variable called to indicate whether y or r has been called
            let called = false; // False means that it has not been called
            try {
                If x is set to unreadable, try/catch is required. If x is set to unreadable, try/catch is required.
                then = x.then;
            } catch (err) {
                // Reject
                reject(err);
            }

            // Determine if then is a function
            if (typeof then === 'function') {
                try {
                    // Change this to point to x
                    then.call(
                        x,
                        y= > {
                            // Exit if y or x has already been called
                            if (called) return;
                            // Change called to called
                            called = true;
                            // Execute the resolvePromise again
                            this.resolvePromise(promise2, y, resolve, reject);
                        },
                        r= > {
                            // Exit if y or x has already been called
                            if (called) return;
                            // Change called to called
                            called = true;
                            // reject the rreject(r); })}catch (e) {
                    // Exit if y or x has already been called
                    if (called) return;
                    // If then makes an error while being called, then it goes in here, reject directlyreject(e); }}else {
                // Resolve with x if then is not a functionresolve(x); }}else {
            // Resolve with x if x is not an object or functionresolve(x); }}static resolve = (value) = > {
        return new Promise((resolve, reject) = >{ resolve(value); })}static reject = (reason) = > {
        return new Promise((resolve, reject) = >{ reject(reason); })}static all = (promises) = > {
        let result = [];
        let count = 0;

        // Check whether the parameter is an array. If it is not an array, the parameter is returned without execution
        if (!Array.isArray(promises)) return promises;

        return new Promise((resolve, reject) = > {
            // Add data to result
            const insertData = (data, index) = > {
                result[index] = data;
                count++;
                // Check whether the execution is complete
                if(count === result.length) { resolve(result); }}// Use a loop to iterate over all promises and execute
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(value= >insertData(value, i), reject); }})}static race = (promises) = > {
        if (!Array.isArray(promises)) return promises;
        return new Promise((resolve, reject) = > {
            for (let i = 0; i < promises.length; i++) { promises[i].then(resolve, reject); }}}})Copy the code