“This is the first day of my participation in the August More Text Challenge.

Promise can be said to be one of the knowledge points that will come out of the interview now. This is not going to be the recruitment season of gold, silver and silver. I will take advantage of this time to review the knowledge points well.

promise

A promise is an object that represents the final completion or failure of an asynchronous operation. Its emergence allows asynchronous operations to be treated like synchronous operations.

The state of the promise

A promise has three states, and its state must be in one of them.

status meaning
pending Initial state, neither success nor failure
fulfilled The successful state
rejected The failure state

By default, a promise’s state is pending, and it changes its current state based on the state of the asynchronous operation. Once the state has changed, it will never change again. Furthermore, a promise’s state can change only in one of two ways:

  1. frompendingintofulfilled
  2. frompendingintorejected

Basic use of Promise

When we use promises, we pass in a function like this:

const promise = new Promise((resolve, reject) = > {});
Copy the code

This function is executed as soon as a Promise instance is created, synchronously

console.log('1');
const promise = new Promise((resolve, reject) = > {
    console.log('2');
});
console.log('3');

/ / 1
/ / 2
/ / 3
Copy the code

In this function, there are two arguments, resolve and reject.

functionName meaning
resolve Is a function that is called when an asynchronous operation succeeds and passes in the result of the successful asynchronous operation as an argumentresolveAt this time,PromiseState will change frompendingintofulfilled
reject Is a function that is called when an asynchronous operation fails and takes an error message or error message as an argumentrejectAt this time,PromiseState will change frompendingintorejected

Handwriting section ① — controls the state of MyPromise

From the above understanding, we started writing our own MyPromise:

// Three states of promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise{

    status = PENDING; // The default state of Promise
    value = null; // The default value for Promise

    // fn is the function we passed in the new Promise, and that function is executed immediately
    // fn has two functions as arguments,
    constructor(fn) {
        // Called on success, and change the state from Pending to depressing
        const resolve = value= > {
            // Because the Promise can only be changed to depressing or Rejected when the state is pending. After the state is changed, the state can never be modified. Therefore, the following operation can be continued only when the current state is pending.
            if(this.status === PENDING){
                this.status = FULFILLED;
                this.value = value; }};// Called when it fails and changes the state from Pending to Rejected
        const reject = reason= > {
            if(this.status === PENDING) {
                this.status = REJECTED;
                this.value = reason; }}; fn(resolve, reject); }}Copy the code

test

// 1. Can I change the state of MyPromise
const promise = new MyPromise((resolve, reject) = > {
    resolve(123);
});
console.log(promise); // MyPromise {status: "fulfilled", value: 123}
// ---
const promise = new MyPromise((resolve, reject) = > {
    reject(123);
});
console.log(promise) // MyPromise {status: "rejected", value: 123}

// 2. Can the function continue to run when an error is thrown inside it
// Promise executes the code after the error and changes the state to Rejected,
const promise = new MyPromise((resolve, reject) = > {
    throw new Error('wrong');
});
console.log(promise);
// The promise value is not output
Copy the code
// omit some code...
class MyPromise{
    // omit some code...
    constructor(fn) {
        // omit some code...

        // fn(resolve, reject) change this line to the following
        / / try... catch... Catch an error, and when there is an error, reject is executed, changing the Promise state to Rejected, and passing the error message as an argument to reject
        try{
            fn(resolve, reject);
        }catch(err){ reject(err); }}}Copy the code

Continue to test

// Whether the function can continue running when an error is thrown inside it
const promise = new MyPromise((resolve, reject) = > {
    throw new Error('wrong');
});
console.log(promise); // MyPromise {status: "rejected", value: Error: Error at http://127.0.0.1:5500/demo.js:33:11 at new MyPromise (http://127.0.0.1:5500/de... }
Copy the code

Now, even if an error is thrown during execution, it will continue to run. And the status is rejected!

Promise.then

The then() method is primarily used to handle callbacks to Promise state changes and return a new Promise.

Note:thenThe functions inside are called asynchronously, not synchronously.

It takes two optional arguments:

functionName meaning
onFulfilled whenPromiseThe state of becomingfulfilledIs called. This function takes one argument to accept the result of success; If the argument is not a function, it is internally replaced byx => xIs returned as isPromiseThe final result of.
onRejected whenPromiseThe state of becomingrejectedThis function takes an argument that accepts the cause of the failure; If the argument is not a function, it is internally replaced bythrowFunction.

Then () returns values as follows:

For more details, click promise.prototype.then()

  • If it returns a value, thenthenThe returnedPromiseWill becomefulfilledAnd take the return value asonFulfilledThe parameters of the
  • If it doesn’t return any value, thenthenThe returnedPromiseWill becomefulfilledAnd will beundefinedAs aonFulfilledThe parameters of the
  • Throw an error, thenthenThe return of thePromiseWill becomerejected, and throws error messages asonRejectedThe parameters of the
  • Returns aPromiseIf so, thenthenThe returnedPromiseThe state is based on thatPromiseIs determined by the state of, and the function argument to be called and thatPromiseThe arguments to the final callback are the same.

Basic usage of promise.then ()

const promise = new Promise((resolve, reject) = > {
    resolve(123);
});
promise.then(res= > {
    console.log(res); / / 123
});

// -----

const promise = new Promise((resolve, reject) = > {
    reject(234);
});
promise.then(res= > {
    console.log('success', res);
}, err= > {
    console.log('failure', err); 234 / / failure
});

// -----

const promise = new Promise((resolve, reject) = > {
    resolve(123);
}).then(res= > {
    console.log(1, res);
}).then(res= > {
    console.log(2, res);
}, err= > {
    console.log(1, err);
}).then(res= > {
    console.log(3, res);
});

/ / 1, 123
// 2 undefined
// 3 undefined

// -----

const promise = new Promise((resolve, reject) = > {
    resolve(123);
}).then(res= > {
    return new Promise((resolve, reject) = > {
        resolve(345)
    })
}).then(res= > {
    console.log(res); / / 345
})

Copy the code

Handwriting part ② — implement then method

/ /...

class MyPromise{
    / /...
    thenables = [];  // Store the successful callback function
    catchables = []; // Store the failed callback function
    constructor(fn){
        const resolve = value= > {
            if (this.status === PENDING) {
                this.status = FULFILLED;
                this.value = value;
                // When the length of the callback array is greater than 0, the array is looped through, executing each callback function in it
                this.thenables.length > 0 && this.thenables.forEach(handle= >handle(value)); }};const reject = reason= > {
            if (this.status === PENDING) {
                this.status = REJECTED;
                this.value = reason;
                this.catchables.length > 0 && this.catchables.forEach(handle= >handle(reason)); }};// ...
    }

    // This is a big pity or fulfilled Promise. // If the Promise is fulfilled fulfilled or fulfilled, then you can perform onFulfilled or fulfilled
    then(onFulfilled, onRejected) {
        // When there is no callback to pass processing, some processing needs to be done
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x= > x;
        onRejected = typeof onRejected === 'function' ? onRejected : err= > { throw err };

        // Return a new promise
        let promise2 = new MyPromise((resolve, reject) = > {
            if (this.status === FULFILLED) {
                setTimeout(() = > {
                    // Used to catch errors
                    try {
                        // Get the result of the callback function execution, then pass ExecCb into the function
                        let x = onFulfilled(this.value);
                        this.ExecCb(x, promise2, resolve, reject);
                    } catch(err) { reject(err); }},0);
            } else if (this.status === REJECTED) {
                setTimeout(() = > {
                    try {
                        let x = onRejected(this.value);
                        this.ExecCb(x, promise2, resolve, reject);
                    } catch(err) { reject(err); }},0)}else {
                // When the current state is pending, we need to store the callback function into an array

                this.thenables.push(() = > {
                    try {
                        let x = onFulfilled(this.value);
                        this.ExecCb(x, promise2, resolve, reject);
                    } catch(err) { reject(err); }});this.catchables.push(() = > {
                    try {
                        let x = onRejected(this.value);
                        this.ExecCb(x, promise2, resolve, reject);
                    } catch(err) { reject(err); }}); }});return promise2;
    }

    ExecCb(x, promise, resolve, reject) {
        // When returning itself, an error message is thrown
        if (x === promise) {
            return reject(new Error('Chaining cycle detected for promise #<Promise>'))}// If x is a Promise object, then the execution executes the then method
        if (x instanceof MyPromise) {
            x.then(data= > resolve(data), err= > reject(err))
        } else {
            // If not, take the value as the resolve argumentresolve(x); }}}Copy the code

Testing:

// Simulate asynchrony
const promise = new MyPromise((resolve, reject) = > {
    setTimeout(() = > {
        resolve(1)},3000)
}).then().then().then(res= > console.log(res));
// Output 1 after 3 seconds

// ---
// Return the case of Promise
const promise = new MyPromise((resolve, reject) = > {
    resolve(123);
}).then(res= > {
    return new MyPromise((resolve, reject) = > {
        resolve(345)
    })
}).then(res= > {
    console.log(res); / / 345
});
Copy the code

To this point, we have almost realized the core functions of Promise, is it a better understanding of it?

Full code: Codesandbox.io/S /hopeful-w…

The code is a little redundant, please forgive me.