1.Promise resolves callback hell: (1) Callback function deferred binding: callback functions are not declared directly, but passed in via the later THEN method, that is, deferred. (2) Return value penetration: Asynchronous methods do not immediately return the final value, but return a promise, which can be followed by chain calls. (3) Error bubbling: The error generated before will be passed backward until it is received by catch.

A simple version of the implementation

// Three states
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(executor){
    let self = this; // Cache the current Promise instance
    self.status = PENDING; // Current status
    self.value = undefined; // The value returned successfully
    self.reason = undefined; // Cause of failure
    self.onFulfilled = undefined; // Successful callback
    self.onRejected = undefined; // Failed callback

    let resolve = (value) = >{
        if (self.status === PENDING){
            setTimeout(() = >{
                self.status = FULFILLED;
                self.value = value;
                self.onFulfilled(self.value);// Execute a successful callback in resolve.
            },0)}}let reject = (reason) = >{
        if (self.status === PENDING){
            setTimeout(() = >{
                self.status = REJECTED;
                self.reason = reason;
                self.onRejected(self.reason);

            },0)}}// If exector executes an error, reject is executed
    try{
        executor(resolve,reject);
    }catch(err){
        reject(err);
    }
}

myPromise.prototype.then = function(onFulfilled,onRejected){
    if (this.status === PENDING){
        this.onFulfilled = onFulfilled;
        this.onRejected = onRejected;
    }
    if (this.status === FULFILLED){
        // If the state is fulfilled, the successful callback will be implemented directly and the successful value will be passed in
        onFulfilled(this.value);
    }
    if (this.status === REJECTED){
        // In the rejected state, the failed callback is executed directly and the failure cause is passed in
        onRejected(this.reason); }}Copy the code

Set to callback array

Set the callback to an array:

self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
Copy the code

The then function adds the callback function to the array when the state is PENDING

if (this.status === PENDING) {
    this.onFulfilledCallbacks.push(onFulfilled);
    this.onRejectedCallbacks.push(onRejected);
Copy the code

Partially modify the execution of the callback function in resolve and Reject:

/ / resolve
self.onFulfilledCallbacks.forEach((callback) = > callback(self.value));
/ / reject
self.onRejectedCallbacks.forEach((callback) = > callback(self.error));
Copy the code

The full code is as follows:

// Three states
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(executor){
    let self = this; // Cache the current Promise instance
    self.status = PENDING; // Current status
    self.value = undefined; // The value returned successfully
    self.reason = undefined; // Cause of failure
    self.onFulfilledCallbacks = []; // Successful callback
    self.onRejectedCallbacks = []; // Failed callback

    let resolve = (value) = >{
        if (self.status === PENDING){
            setTimeout(() = >{
                self.status = FULFILLED;
                self.value = value;
                self.onFulfilledCallbacks.forEach((callback) = >{callback(this.value)});// Execute successful callbacks in order to resolve.
            },0)}}let reject = (reason) = >{
        if (self.status === PENDING){
            setTimeout(() = >{
                self.status = REJECTED;
                self.reason = reason;
                self.onRejectedCallbacks((callback) = >{callback(self.reason)});
            },0)}}// If exector executes an error, reject is executed
    try{
        executor(resolve,reject);
    }catch(err){
        reject(err);
    }
}

myPromise.prototype.then = function(onFulfilled,onRejected){
    if (this.status === PENDING){
        this.onFulfilledCallbacks.push(onFulfilled);
        this.onRejectedCallbacks.push(onRejected);
    }
    if (this.status === FULFILLED){
        // If the state is fulfilled, the successful callback will be implemented directly and the successful value will be passed in
        onFulfilled(this.value);
    }
    if (this.status === REJECTED){
        // In the rejected state, the failed callback is executed directly and the failure cause is passed in
        onRejected(this.reason);
    }
    return this;
}
Copy the code

Solve the chain call

1. By default, we return a promise in the first THEN. • If a promise is returned, it is passed to the next THEN. • If a normal value is returned, the normal value is passed to the next THEN. 2. If we return a parameter in the first then. This new promise that comes out of return is onFulfilled() or onRejected()

The secret states the value of onFulfilled() or onRejected(), which is the value returned by the first THEN. This is called X, and the function to judge X is called resolvePromise

// Three states
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(executor) {
    let self = this; // Cache the current myPromise instance
    self.status = PENDING; // Current status
    self.value = undefined; // The value returned successfully
    self.reason = undefined; // Cause of failure
    self.onFulfilledCallbacks = []; // Successful callback
    self.onRejectedCallbacks = []; // Failed callback

    let resolve = (value) = > {
        if (self.status === PENDING) {
            setTimeout(() = > {
                self.status = FULFILLED;
                self.value = value;
                self.onFulfilledCallbacks.forEach((callback) = > { callback(this.value) });// Execute successful callbacks in order to resolve.
            }, 0)}}let reject = (reason) = > {
        if (self.status === PENDING) {
            setTimeout(() = > {
                self.status = REJECTED;
                self.reason = reason;
                self.onRejectedCallbacks.forEach((callback) = > { callback(self.reason) });

            }, 0)}}// If exector executes an error, reject is executed
    try {
        executor(resolve, reject);
    } catch (err) {
        reject(err);
    }
}

myPromise.prototype.then = function (onFulfilled, onRejected) {
    // ondepressing, onRejected are both optional parameters. If they are not functions, they must be ignored
    // this is a big pity. This is a big pity. This is a big pity
    This is a big pity. // • onRejected returns a common value. If value => value, then this will run into the next onpity

    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason= > { throw reason };

    let bridgemyPromise;
    let self = this;
    if (self.status === PENDING) {
        return bridgemyPromise = new myPromise((resolve, reject) = > {
            self.onFulfilledCallbacks.push((value) = > {
                setTimeout(() = > {
                    try {
                        let x = onFulfilled(value);
                        resolvemyPromise(bridgemyPromise, x, resolve, reject);
                    } catch(reason) { reject(reason); }},0)}); self.onRejectedCallbacks.push((reason) = > {
                setTimeout(() = > {
                    try {
                        let x = onRejected(reason);
                        resolvemyPromise(bridgemyPromise, x, resolve, reject);
                    } catch(e) { reject(e); }},0)})})}if (this.status === FULFILLED) {
        // If the state is fulfilled, the successful callback will be implemented directly and the successful value will be passed in
        return bridgemyPromise = new myPromise((resolve, reject) = > {
            setTimeout(() = > {
                try {
                    let x = onFulfilled(self.value);
                    resolvemyPromise(bridgemyPromise, x, resolve, reject);
                }
                catch(reason) { reject(reason); }},0)})}if (this.status === REJECTED) {
        // In the rejected state, the failed callback is executed directly and the failure cause is passed in
        return bridgemyPromise = new myPromise((resolve, reject) = > {
            setTimeout(() = > {
                try {
                    let x = onRejected(self.reason);
                    resolvemyPromise(bridgemyPromise, x, resolve, reject);
                }
                catch(reason) { reject(reason); }})})}return bridgemyPromise;
}
Copy the code

One of the important functions implemented is:

// Compatible with multiple myPromise implementations
function resolvemyPromise(bridgemyPromise, x, resolve, reject) {
    // Prevent circular reference problems
    if (bridgemyPromise === x) {
        return reject(new TypeError('Error'));
    }
    // called variable, used to determine whether the function has been called
    let called;
    // Determine whether x is an object or a function, and if neither is, pass x to resolve
    if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            If x is an object or a function, assign x. Chen to then, and then determine the type. If x is not a function, pass x to resolve
            let then = x.then;
            // If then is a function, it defaults to myPromise
            if (typeof then === 'function') {
                // Execute then with this as the first argument, followed by a successful callback and a failed callback
                then.call(x, y= > {
                    if (called) return;
                    called = true;
                    resolvemyPromise(bridgemyPromise, x, resolve, reject);
                }, reason= > {
                    if (called) return;
                    called = true; reject(reason); })}else{ resolve(x); }}catch (reason) {
            if (called) return;
            called = true; reject(reason); }}else{ resolve(x); }}Copy the code

4. Address error capture and bubbling mechanisms

Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
}
Copy the code

5. Catch and resolve, Reject, race, and All

(1) developer.mozilla.org/zh-CN/docs/… (2) www.cnblogs.com/sugar-tomat… (3) juejin. Cn/post / 684490…