Promise系列三 - 实现Promise(all、allSettled、race、any类方法)

179 阅读3分钟

一、resolve和reject类方法

  • 定义类的静态方法
    static resolve(value) {
      return new MyPromise(resolve => resolve(value))
    }
    
    static reject(reason) {
      return new MyPromise((resolve, reject) => reject(reason))
    }
    
    MyPromise.resolve('resolve message').then(res => {
      console.log(res); //resolve message
    });
    
    MyPromise.reject('reject message').catch(err => {
      console.log(err); //reject message
    });
    

二、all和allSettled类方法

前面:

const p1 = new MyPromise(resolve => {
  setTimeout(() => {
    resolve('111111p')
  }, 1000)
});

const p2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    // resolve('2222p')
    reject('2222p')
  }, 2000)
});

const p3 = new MyPromise(resolve => {
  setTimeout(() => {
    resolve('3333p')
  }, 3000)
});

2.1. all

  • 什么时候执行resolve,什么时候执行reject?
  • 当所有promise有结果了resolve了,就调用resolve;
  • 当执行过程中出现reject,那么就调用reject;
    static all(promises) {
      const values = [];
    
      return new MyPromise((resolve, reject) => {
        promises.forEach(promise => {
          promise.then(res => {
            const newLegh = values.push(res);
    
            if (newLegh === promises.length) {
              resolve(values);
            }
          }, err => {
            reject(err);
          });
        });
      });
    }
    
    MyPromise.all([p1, p2, p3]).then(res => {
      console.log('res: ', res); //res:  [ '111111p', '2222p', '3333p' ]
    }).catch(err => {
      console.log('err: ', err); //err:  2222p
    });
    

2.2. allSettled

  • 不管执行过程中走了resolve还是reject都需要执行完才resolve;
    static allSettled(promises) {
      return new MyPromise(resolve => {
        const results = [];
    
        promises.forEach(promise => {
          promise.then(res => {
            results.push({ status: STATUS_FUFILLED, value: res });
    
            if (results.length === promises.length) {
              resolve(results)
            };
          }, err => {
            results.push({ status: STATUS_REJECTED, reason: err });
    
            if (results.length === promises.length) {
              resolve(results)
            };
          });
        });
      });
    }
    
    MyPromise.allSettled([p1, p2, p3]).then(res => {
      console.log('res: ', res);
      /*
          res:  [
                  { status: 'fulfilled', value: '111111p' },
                  { status: 'rejected', reason: '2222p' },
                  { status: 'fulfilled', value: '3333p' }
                ]
      */
    });
    

三、race和any类方法

3.1. race

  • 谁先有结果,那么就使用谁的结果;
    static race(promises) {
      return new MyPromise((resolve, reject) => {
        promises.forEach(promise => {
          // promise.then(res => {
          //   resolve(res)
          // }, err => {
          //   reject(err)
          // })
          //等同于
          promise.then(resolve, reject);
        });
      });
    }
    
    const p1 = new MyPromise(resolve => {
      setTimeout(() => {
        resolve('111111p')
      }, 1000)
    });
    
    const p2 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        // resolve('2222p')
        reject('2222p')
      }, 800)
    });
    
    const p3 = new MyPromise(resolve => {
      setTimeout(() => {
        resolve('3333p')
      }, 2000)
    });
    
    MyPromise.race([p1, p2, p3]).then(res => {
      console.log('res: ', res);
    }).catch(err => {
      console.log('err: ', err); //err:  2222p
    });
    

3.2. any

  • any方法会等到一个fulfilled状态,才会决定新Promise的状态;
  • 如果所有的Promise都是reject的,那么会报一个AggregateError的错误;
    static any(promises) {
      return new MyPromise((resolve, reject) => {
        const reasons = [];
    
        promises.forEach(promise => {
          promise.then(res => {
            resolve(res);
          }, err => {
            reasons.push(err);
    
            if (reasons.length === promises.length) {
              reject(new AggregateError(reasons));
            }
          });
        });
      });
    }
    
    const p1 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        // resolve('111111p')
        reject('111111p')
      }, 1000)
    });
    
    const p2 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        // resolve('2222p')
        reject('2222p')
      }, 800)
    });
    
    const p3 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        // resolve('3333p')
        reject('3333p')
      }, 2000)
    });
    
    MyPromise.any([p1, p2, p3]).then(res => {
      console.log('res: ', res); //res:  2222p
    }).catch(err => {
      console.log('err: ', err); //err:  AggregateError
      console.log('err: ', err.errors); //err:  [ '2222p', '111111p', '3333p' ]
    });
    

3.3. 完整代码

const STATUS_PENDING = 'pending';
const STATUS_FUFILLED = 'fulfilled';
const STATUS_REJECTED = 'rejected';

function execFnWithCatchErr(execFn, value, resolve, reject) {
  try {
    const result = execFn(value);
    resolve(result);
  } catch (err) {
    reject(err);
  }
};

class MyPromise {
  constructor(executor) {
    this.state = STATUS_PENDING;
    this.value = undefined;
    this.reason = undefined;
    
    this.onFufilledFns = [];
    this.onRejectedFns = [];

    const resolve = (value) => {
      if (this.state === STATUS_PENDING) {
        
        queueMicrotask(() => {
          if (this.state !== STATUS_PENDING) return;
          this.state = STATUS_FUFILLED;
          this.value = value;
          this.onFufilledFns.forEach(fn => {
            fn(this.value)
          });
        });
      }
    }
    
    const reject = (reason) => {
      if (this.state === STATUS_PENDING) {
        
        queueMicrotask(() => {
          if (this.state !== STATUS_PENDING) return;
          this.state = STATUS_REJECTED;
          this.reason = reason;
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          });
        });
      }
    }

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFufilled, onRejected) {
    const defaultOnRejected = err => { throw err };
    onRejected = onRejected || defaultOnRejected;

    const defaultOnFulfilled = value => { return value };
    onFufilled = onFufilled || defaultOnFulfilled;

    return new MyPromise((resolve, reject) => {
      if (this.state === STATUS_FUFILLED && onFufilled) {
        execFnWithCatchErr(onFufilled, this.value, resolve, reject)
      };
      if (this.state === STATUS_REJECTED && onRejected) {
        execFnWithCatchErr(onRejected, this.reason, resolve, reject)
      };

      if (this.state === STATUS_PENDING) {
        if (onFufilled) this.onFufilledFns.push(() => {
          execFnWithCatchErr(onFufilled, this.value, resolve, reject)
        });
        if (onRejected) this.onRejectedFns.push(() => {
          execFnWithCatchErr(onRejected, this.reason, resolve, reject)
        });
      }
    })
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  finally(onFinally) {
    this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }

  static resolve(value) {
    return new MyPromise(resolve => resolve(value));
  }

  static reject(reason) {
    return new MyPromise((resolve, reject) => reject(reason));
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const values = [];

      promises.forEach(promise => {
        promise.then(res => {
          const newLegh = values.push(res);
          if (newLegh === promises.length) {
            resolve(values);
          }
        }, err => {
          reject(err);  
        });
      });
    });
  }

  static allSettled(promises) {
    return new MyPromise(resolve => {
      const results = [];

      promises.forEach(promise => {
        promise.then(res => {
          results.push({ status: STATUS_FUFILLED, value: res });

          if (results.length === promises.length) {
            resolve(results)
          };
        }, err => {
          results.push({ status: STATUS_REJECTED, reason: err });
          
          if (results.length === promises.length) {
            resolve(results)
          };
        });
      });
    });
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, reject);
      });
    });
  }

  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const reasons = [];

      promises.forEach(promise => {
        promise.then(res => {
          resolve(res);
        }, err => {
          reasons.push(err);
          if (reasons.length === promises.length) {
            reject(new AggregateError(reasons));
          }
        });
      });
    });
  }
  
};

四、其它

相关文章:Promise中的类方法