1. Core logic analysis

  1. A Promise is a class that when you execute that class you pass in an executor and that executor executes immediately
  2. There are three states in Promise: successful depressing failed waiting pending
    • pending -> fulfilled
    • pending -> rejected
    • Once the state is determined, it cannot be changed
  3. The resolve and reject functions are used to change state
    • resolve: fulfilled
    • reject: rejected
  4. What the then method does internally is determine the state and if the state is a successful call to a successful callback and if the state is a failure call to a failed callback the then method is defined in the prototype object
  5. Then a successful callback takes one parameter to indicate the value after success. Then a failed callback takes one parameter to indicate the reason for failure
  6. The then methods under the same Promise object can be called multiple times
  7. The then method can be called chained. The callback of the later THEN method returns the value of the callback of the previous THEN method
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail

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

    status = PENDING; / / state
    value = undefined; // Then function successfully callback required arguments
    reason = undefined; // Then function fails to call back the argument required

    resolve = value= > {
        // If the state is not waiting to prevent the program from executing down
        if(this.status ! == PENDING)return;
        // Change the status to success
        this.status = FULFILLED;
        // Save the value after success
        this.value = value;
    }

    reject = reason= > {
        // If the state is not waiting to prevent the program from executing down
        if(this.status ! == PENDING)return;
        // Change the status to failed
        this.status = REJECTED;
        // Cause of save failure
        this.reason = reason;
    }

    then = (successCallback, failCallback) = > {
        // Determine the status
        if(this.status === FULFILLED) {
            successCallback(this.value);
        } else if(this.status === REJECTED) {
            failCallback(this.reason); }}}module.exports = MyPromise;
Copy the code

Two, asynchronous call solution

1. The scene

const promise = new MyPromise((resolve, reject) = > {
    setTimeout(() = > {
        resolve('success');
    }, 2000);
});
promise.then(value= > {
    console.log(value);
}, reason= > {
    console.log(reason);
});
Copy the code

2. Implementation step analysis

  • The timer callback function is asynchronous execution code
  • The then function executes in a state still pending
  • Add execution logic to the THEN function when the state is pending, and store successful and failed callbacks to be called in the resolve and Reject functions

3. Code implementation

class MyPromise {... successCallback =undefined; // Successful callback
    failCallback = undefined; // Failed callback

    resolve = value= >{...// if a successful callback exists
        this.successCallback && this.successCallback(value);
    }

    reject = reason= >{...// if the failed callback exists
        this.failCallback && this.failCallback(reason);
    }

    then = (successCallback, failCallback) = > {
        // Determine the status
        if(this.status === FULFILLED) {
            ...
        } else {
            / / wait for
            // Store the success and failure callbacks
            this.successCallback = successCallback;
            this.failCallback = failCallback; }}}Copy the code

3. Multiple calls to then

1. The scene

promise.then(value= > {
    console.log(value);
});
promise.then(value= > {
    console.log(value);
});
promise.then(value= > {
    console.log(value);
});
Copy the code

2. Implementation step analysis

  • Then multiple calls to synchronous code require no special handling, whereas asynchronous code requires special handling
  • That is, when THEN is called multiple times, the callback for each call is stored
  • When the status changes to success or failure, the stored callbacks are executed in turn

3. Code implementation

class MyPromise {... successCallback = [];// Successful callback
    failCallback = []; // Failed callback

    resolve = value= >{...// if a successful callback exists
        // this.successCallback && this.successCallback(value);
        while (this.successCallback.length) this.successCallback.shift()(this.value)
    }

    reject = reason= >{...// if the failed callback exists
        // this.failCallback && this.failCallback(reason);
        while (this.failCallback.length) this.failCallback.shift()(this.reason)
    }

    then = (successCallback, failCallback) = > {
        // Determine the status
        if(this.status === FULFILLED) {
            ...
        } else {
            / / wait for
            // Store the success and failure callbacks
            this.successCallback.push(successCallback);
            this.failCallback.push(failCallback); }}}Copy the code

Chain calls to THEN

1. The scene

promise.then(value= > {
    console.log(value);
    return 100;
}).then(value= > {
    console.log(value);
}).then(value= > {
    console.log(value);
});
Copy the code

2. Implementation step analysis

  • Chained calls to the THEN methods must return a Promise object for each then method
  • Pass the return value of the previous THEN method to the next THEN method (you need to determine if the return value is a Promise object)

3. Code implementation

class MyPromise {... then =(successCallback, failCallback) = > {
        const promise2 = new MyPromise((resolve, reject) = > {
            // Determine the status
            if (this.status === FULFILLED) {
                const x = successCallback(this.value);
                // Determine whether x is a normal value or a Promise object
                // If it is a normal value, call resolve directly
                // If it is a Promise object, see the result returned by the Promise object
                // Call resolve or reject based on the result returned by the Promise object
                resolvePromise(x, resolve, reject);
            } else if (this.status === REJECTED) {
                failCallback(this.reason);
            } else {
                / / wait for
                // Store the success and failure callbacks
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback); }});returnpromise2; }}function resolvePromise(x, resolve, reject) {
    if(x instanceof MyPromise) {
        / / promise object
        // x.then(value => resolve(value), reason => reject(reason));
        x.then(resolve, reject);
    } else {
        / / common valuesresolve(x); }}Copy the code

4, the chain call then cannot pass the current promise

1. The scene

let p1 = promise.then(value= > {
    console.log(value);
    return p1;
})
Copy the code

2. Implementation step analysis

  • A Promise object returned by the current THEN method cannot be returned in the THEN method

3. Code implementation

class MyPromise {... then =(successCallback, failCallback) = > {
        const promise2 = new MyPromise((resolve, reject) = > {
            // Determine the status
            if (this.status === FULFILLED) {
                setTimeout(() = > {
                    const x = successCallback(this.value);
                    // Determine whether x is a normal value or a Promise object
                    // If it is a normal value, call resolve directly
                    // If it is a Promise object, see the result returned by the Promise object
                    // Call resolve or reject based on the result returned by the Promise object
                    // The new object is not returned as the promise2 object, so it needs to be called asynchronously
                    resolvePromise(promise2, x, resolve, reject);
                }, 0);
            } else if (this.status === REJECTED) {
                ...
            } else{... }});returnpromise2; }}function resolvePromise(promise2, x, resolve, reject) {
    if(promise2 === x) {
        return reject(new TypeError("Chaining cycle detected for promise #<Promise>")); }... }Copy the code

5. Exception handling

1. The scene

For code robustness, appropriate error handling should be done in place

2. Implementation step analysis

  • When the constructor calls the executor
  • When a success or failure callback executes an error, the next Promise reject method is called to pass the error message along

3. Code implementation

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject);
        } catch (e) {
            this.reject(e); }}... resolve =value= >{...while (this.successCallback.length) this.successCallback.shift()();
    }

    reject = reason= >{...while (this.failCallback.length) this.failCallback.shift()();
    }
    then = (successCallback, failCallback) = > {
        const promise2 = new MyPromise((resolve, reject) = > {
            // Determine the status
            if (this.status === FULFILLED) {
                setTimeout(() = > {
                    try {
                        const x = successCallback(this.value);
                        // Determine whether x is a normal value or a Promise object
                        // If it is a normal value, call resolve directly
                        // If it is a Promise object, see the result returned by the Promise object
                        // Call resolve or reject based on the result returned by the Promise object
                        // Call asynchronously (setTimeout = 1); // Call asynchronously (setTimeout = 1)
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        Call the next Promise's reject method manually if an error occursreject(e); }},0);
            } else if (this.status === REJECTED) {
                setTimeout(() = > {
                    try {
                        const x = failCallback(this.reason);;
                        // Determine whether x is a normal value or a Promise object
                        // If it is a normal value, call resolve directly
                        // If it is a Promise object, see the result returned by the Promise object
                        // Call resolve or reject based on the result returned by the Promise object
                        // Call asynchronously (setTimeout = 1); // Call asynchronously (setTimeout = 1)
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        Call the next Promise's reject method manually if an error occursreject(e); }},0);
            } else {
                / / wait for
                // Store the success and failure callbacks
                this.successCallback.push(() = > {
                    setTimeout(() = > {
                        try {
                            const x = successCallback(this.value);
                            // Determine whether x is a normal value or a Promise object
                            // If it is a normal value, call resolve directly
                            // If it is a Promise object, see the result returned by the Promise object
                            // Call resolve or reject based on the result returned by the Promise object
                            // Call asynchronously (setTimeout = 1); // Call asynchronously (setTimeout = 1)
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            Call the next Promise's reject method manually if an error occursreject(e); }},0);
                });
                this.failCallback.push(() = > {
                    setTimeout(() = > {
                        try {
                            const x = failCallback(this.reason);;
                            // Determine whether x is a normal value or a Promise object
                            // If it is a normal value, call resolve directly
                            // If it is a Promise object, see the result returned by the Promise object
                            // Call resolve or reject based on the result returned by the Promise object
                            // The new object is not returned as the promise2 object, so it needs to be called asynchronously
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            Call the next Promise's reject method manually if an error occursreject(e); }},0); }); }});returnpromise2; }}Copy the code

6. Then method parameters become optional

1. The scene

const promise = new MyPromise((resolve, reject) = > {
    resolve(100);
});
promise.then().then().then(value= > console.log(value), reason= > console.log(reason));
Copy the code

2. Implementation step analysis

  • Arguments to the THEN method are optional
  • If you pass everything in, you pass the value, you pass a function value=>value, okay
  • Therefore, the corresponding parameter can be judged in the THEN function

3. Code implementation

class MyPromise {... then =(successCallback, failCallback) = > {
        successCallback = successCallback ? successCallback : value= > value;
        failCallback = failCallback ? failCallback : reason= > { throwreason; }; . }}Copy the code

Static method all

1. The scene

function p1 () {
  return new MyPromise(function (resolve, reject) {
    setTimeout(function () {
      resolve('p1')},2000)})}function p2 () {
  return new MyPromise(function (resolve, reject) {
    reject('failure')
    // resolve(' resolve ');
  })
}
MyPromise.all(['a'.'b', p1(), p2(), 'c']).then(result= > {
  // result -> ['a', 'b', 'p1', 'p2', 'c']
})
Copy the code

2. Implementation step analysis

  • Returns the result of execution in the order in which the array was passed
  • The all method also returns a Promise object that can continue the chain call to THEN
  • The all method passes in an array that fails if one of its executions fails

3. Code implementation

static all (array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) = > {
      function addData (key, value) {
        result[key] = value;
        index++;
        if(index === array.length) { resolve(result); }}for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          / / promise object
          current.then(value= > addData(i, value), reason= > reject(reason))
        }else {
          / / common valuesaddData(i, array[i]); }}})}Copy the code

Resolve ()

1. The scene

MyPromise.resolve(100).then(value= > console.log(value)); / / 100
Copy the code

2. Implementation step analysis

  • Converts the given value to a Promise object, which returns a Promise object

3. Code implementation

static resolve (value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve= > resolve(value));
}
Copy the code

The prototype method finally

1. The scene

2. Implementation step analysis

  • The callback to the finally method is executed regardless of whether the current promise object ends up ina successful or failed state
  • A chain call to the then method, followed by the finally method, gets the final return of the current Promise object

3. Code implementation

finally (callback) {
    return this.then(value= > {
        return MyPromise.resolve(callback()).then(() = > value);
    }, reason= > {
        return MyPromise.resolve(callback()).then(() = > { throw reason })
    })
}
Copy the code

10. Prototype method catch

1. The scene

function p1 () {
    return new Promise(function (resolve, reject) {
        reject('hello');
    })
}
p1()
    .then(value= > console.log(value))
    .catch(reason= > console.log(reason))
Copy the code

2. Implementation step analysis

  • Used to handle cases where the current promise object ends up in a failed state
  • The current THEN method does not pass a failure callback and can be followed by a chain call to catch

3. Code implementation

catch (failCallback) {
    return this.then(undefined, failCallback)
}
Copy the code

Xi. Closure

// Attach the complete code
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail

class MyPromise {
  constructor (executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e); }}/ / promsie state
  status = PENDING;
  // Value after success
  value = undefined;
  // Cause of failure
  reason = undefined;
  // Successful callback
  successCallback = [];
  // Failed callback
  failCallback = [];

  resolve = value= > {
    // If the state is not waiting to prevent the program from executing down
    if (this.status ! == PENDING)return;
    // Change the status to success
    this.status = FULFILLED;
    // Save the value after success
    this.value = value;
    // Determine if the successful callback exists
    // this.successCallback && this.successCallback(this.value);
    while(this.successCallback.length) this.successCallback.shift()()
  }
  reject = reason= > {
    // If the state is not waiting to prevent the program from executing down
    if (this.status ! == PENDING)return;
    // Change the status to failed
    this.status = REJECTED;
    // Cause of save failure
    this.reason = reason;
    // Determine if the failed callback exists
    // this.failCallback && this.failCallback(this.reason);
    while(this.failCallback.length) this.failCallback.shift()()
  }
  then (successCallback, failCallback) {
    // Parameters are optional
    successCallback = successCallback ? successCallback : value= > value;
    // Parameters are optional
    failCallback = failCallback ? failCallback: reason= > { throw reason };
    let promsie2 = new MyPromise((resolve, reject) = > {
      // Determine the status
      if (this.status === FULFILLED) {
        setTimeout(() = > {
          try {
            let x = successCallback(this.value);
            // Determine whether x is a normal value or a promise object
            // Call resolve directly if it is a normal value
            // If it is a Promise object, look at the results returned by promsie
            // Call resolve or reject based on the result returned by the Promise object
            resolvePromise(promsie2, x, resolve, reject)
          }catch(e) { reject(e); }},0)}else if (this.status === REJECTED) {
        setTimeout(() = > {
          try {
            let x = failCallback(this.reason);
            // Determine whether x is a normal value or a promise object
            // Call resolve directly if it is a normal value
            // If it is a Promise object, look at the results returned by promsie
            // Call resolve or reject based on the result returned by the Promise object
            resolvePromise(promsie2, x, resolve, reject)
          }catch(e) { reject(e); }},0)}else {
        / / wait for
        // Store the success and failure callbacks
        this.successCallback.push(() = > {
          setTimeout(() = > {
            try {
              let x = successCallback(this.value);
              // Determine whether x is a normal value or a promise object
              // Call resolve directly if it is a normal value
              // If it is a Promise object, look at the results returned by promsie
              // Call resolve or reject based on the result returned by the Promise object
              resolvePromise(promsie2, x, resolve, reject)
            }catch(e) { reject(e); }},0)});this.failCallback.push(() = > {
          setTimeout(() = > {
            try {
              let x = failCallback(this.reason);
              // Determine whether x is a normal value or a promise object
              // Call resolve directly if it is a normal value
              // If it is a Promise object, look at the results returned by promsie
              // Call resolve or reject based on the result returned by the Promise object
              resolvePromise(promsie2, x, resolve, reject)
            }catch(e) { reject(e); }},0)}); }});return promsie2;
  }
  finally (callback) {
    return this.then(value= > {
      return MyPromise.resolve(callback()).then(() = > value);
    }, reason= > {
      return MyPromise.resolve(callback()).then(() = > { throw reason })
    })
  }
  catch (failCallback) {
    return this.then(undefined, failCallback)
  }
  static all (array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) = > {
      function addData (key, value) {
        result[key] = value;
        index++;
        if(index === array.length) { resolve(result); }}for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          / / promise object
          current.then(value= > addData(i, value), reason= > reject(reason))
        }else {
          / / common valuesaddData(i, array[i]); }}})}static resolve (value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve= >resolve(value)); }}function resolvePromise (promsie2, x, resolve, reject) {
  if (promsie2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (x instanceof MyPromise) {
    / / promise object
    // x.then(value => resolve(value), reason => reject(reason));
    x.then(resolve, reject);
  } else {
    / / common valuesresolve(x); }}module.exports = MyPromise;
Copy the code

Support original, do not copy