新鲜出炉的手写Promise

105 阅读5分钟

Promise

创建MyPromise类,通过es6中class.

  • executor中有两个参数
  • 两种执行回调,一种是成功回调resolve,一种是失败回调reject
class MyPromise {
	constructor(executor) {
        // 成功回调
        const resolve = (value) => {};
        // 失败回调
        const reject = (reason) => {};
        // 执行器立即执行resolve/reject
	executor(resolve, reject);
    }
}

Promise 中有三个状态: pending、fulfilled、rejected

  • pending 初始状态,可以改变为fulfilled(成功)和rejected(失败)
  • fulfilled 成功状态, 操作已成功,且有一个value 值
  • rejected 拒绝状态,操作已失败,且有一个reason原因值
  • promise 的状态只能改变一次,即改变之后都不会在改变
  • promise 中有错误throw抛出的话相当于 rejected
class MyPromise {
        static #PROMISE_STATUS_PENDING = "pending";
  	static #PROMISE_STATUS_FULFILLED = "fulfilled";
  	static #PROMISE_STATUS_REJECTED = "rejected";
	constructor(executor) {
        this.status = MyPromise.#PROMISE_STATUS_PENDING;
        this.value = undefined;
    	this.reason = undefined;
        // 成功回调
        const resolve = (value) => {
            if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {}
        };
        // 失败回调
        const reject = (reason) => {
            if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {}
        };
        // 执行器立即执行resolve/reject
	executor(resolve, reject);
    }
}

then

then 方法可以传入两个参数,当状态为fulfilled时执行,当状态为rejected时执行

class MyPromise {
        static #PROMISE_STATUS_PENDING = "pending";
  	static #PROMISE_STATUS_FULFILLED = "fulfilled";
  	static #PROMISE_STATUS_REJECTED = "rejected";
	constructor(executor) {...}
        // then 方法 有两个参数 onFulfilled onRejected
        then(onFulfilled, onRejected) {
            // 状态为fulfilled,执行onFulfilled,传入成功的值
            if (this.status === MyPromise.#PROMISE_STATUS_FULFILLED) {
        	onFulfilled(this.value);
            }
            // 状态为rejected,执行onRejected,传入失败原因
            if (this.status === MyPromise.#PROMISE_STATUS_REJECTED) {
        	onRejected(this.reason);
            }
	}
}

异步问题,当resolve/reject在异步中执行时,当status还是pending初始状态应该将onFulfilled/onRejected成功或者失败回调存入数组中,等待状态改变,再调用他们.

  • promise中then方法为微任务,可以使用queueMicrotask来模拟微任务
  • 当同时调用resolve/reject时,会同时触发,因此要加不是pending状态时return出去
class MyPromise {
        static #PROMISE_STATUS_PENDING = "pending";
  	static #PROMISE_STATUS_FULFILLED = "fulfilled";
  	static #PROMISE_STATUS_REJECTED = "rejected";
    constructor(executor) {
        this.status = MyPromise.#PROMISE_STATUS_PENDING;
    	this.value = undefined;
    	this.reason = undefined;
    	this.onFulfilledFns = [];
    	this.onRejectedFns = [];
        const resolve = (value) => {
            if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
                // 微任务
            	queueMicrotask(() => {
                // 加if判断不为pending不执行下面代码
                    if (this.status !== MyPromise.#PROMISE_STATUS_PENDING) return;
                    this.status = MyPromise.#PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    this.onFulfilledFns.forEach((fn) => fn(this.value));
            	});
            }
    	};
        const reject = (reason) => {
            if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
                queueMicrotask(() => {
                  if (this.status !== MyPromise.#PROMISE_STATUS_PENDING) return;
                  this.status = MyPromise.#PROMISE_STATUS_REJECTED;
                  this.reason = reason;
                  this.onRejectedFns.forEach((fn) => fn(this.reason));
                });
             }
        };
    }
    // then 方法 有两个参数 onFulfilled onRejected
    then(onFulfilled, onRejected) {
        // 状态为fulfilled,执行onFulfilled,传入成功的值
      	if (this.status === MyPromise.#PROMISE_STATUS_FULFILLED) {
            onFulfilled(this.value);
      	}
       	// 状态为rejected,执行onRejected,传入失败的原因
     	if (this.status === MyPromise.#PROMISE_STATUS_REJECTED) {
            onRejected(this.reason);
      	}
    	// status还是pending初始状态,存入对应数组中
	if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
            this.onFulfilledFns.push(onFulfilled(this.value));
            this.onRejectedFns.push(onRejected(this.reason));
      	}
    }
}

promise 常用的特点就是链式调用,解决回调地狱

  • 在then里面返回新的promise,传递给下个then中
  • 如果返回是一个普通值,直接传递给下个then
  • 无论是在onFulfilled或者onRejected中返回都是传递给下个then中的onFulfilled里
  • 只有抛出错误才会走onRejected里面
class MyPromise {
    static #PROMISE_STATUS_PENDING = "pending";
    static #PROMISE_STATUS_FULFILLED = "fulfilled";
    static #PROMISE_STATUS_REJECTED = "rejected";
    constructor(executor) {...}
    // then 方法 有两个参数 onFulfilled onRejected
    then(onFulfilled, onRejected) {
       return new MyPromise((resolve, reject) => {
          // 状态为fulfilled,执行onFulfilled,传入成功的值
          if (this.status === MyPromise.#PROMISE_STATUS_FULFILLED) {
                  MyPromise.#catchFunctionExecutor(onFulfilled, this.value, resolve, reject);
           }
          // 状态为rejected,执行onRejected,传入失败的原因
          if (this.status === MyPromise.#PROMISE_STATUS_REJECTED) {
                  MyPromise.#catchFunctionExecutor(onRejected, this.reason, resolve, reject);
           }
           // status还是pending初始状态,存入对应数组中
           if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
                this.onFulfilledFns.push(()=>{
                    MyPromise.#catchFunctionExecutor(onFulfilled, this.value, resolve, reject);
                 });
                this.onRejectedFns.push(()=>{
                    MyPromise.#catchFunctionExecutor(onRejected, this.reason, resolve, reject);
                 });
             }
          })
        }
	// 错误捕获执行器
  	static #catchFunctionExecutor(method, value, resolve, reject) {
            try {
                const result = method(value);
                resolve(result);
            } catch (e) {
                reject(e);
            }
        }
}

catch

promise中的catch也是捕获错误的一种,和then中的onRejected作用相当

  • 当then中的参数只有onRejected时,我们需要在then中添加默认值,第一个值onFulfilled不传为undefined会影响我们调onFulfilled,因此加个默认值
class MyPromise {
    static #PROMISE_STATUS_PENDING = "pending";
    static #PROMISE_STATUS_FULFILLED = "fulfilled";
    static #PROMISE_STATUS_REJECTED = "rejected";
    constructor(executor) {...}
    // then 方法 有两个参数 onFulfilled onRejected
    then(onFulfilled, onRejected) {
        const defaultOnFulfilled = (value) => value;
    	const defaultOnRejected = (error) => {throw error;};
    	onFulfilled ||= defaultOnFulfilled;
    	onRejected ||= defaultOnRejected;
        return new MyPromise((resolve, reject) => {
            // 状态为fulfilled,执行onFulfilled,传入成功的值
            if (this.status === MyPromise.#PROMISE_STATUS_FULFILLED) {
                MyPromise.#catchFunctionExecutor(onFulfilled, this.value, resolve, reject);
            }
            // 状态为rejected,执行onRejected,传入失败的原因
            if (this.status === MyPromise.#PROMISE_STATUS_REJECTED) {
                MyPromise.#catchFunctionExecutor(onRejected, this.reason, resolve, reject);
            }
            // status还是pending初始状态,存入对应数组中
            if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
                this.onFulfilledFns.push(()=>{
                    MyPromise.#catchFunctionExecutor(onFulfilled, this.value, resolve, reject);
                });
                this.onRejectedFns.push(()=>{
                    MyPromise.#catchFunctionExecutor(onRejected, this.reason, resolve, reject);
                });
            }
    	})
    }
    catch(onRejected) {
    	return this.then(undefined, onRejected);
    }
    // 错误捕获执行器
    static #catchFunctionExecutor(method, value, resolve, reject) {...}
}

finally

promise中的finally不论状态为成功还是失败都会执行

class MyPromise {
    static #PROMISE_STATUS_PENDING = "pending";
    static #PROMISE_STATUS_FULFILLED = "fulfilled";
    static #PROMISE_STATUS_REJECTED = "rejected";
    constructor(executor) {...}
    // then 方法 有两个参数 onFulfilled onRejected
    then(onFulfilled, onRejected) {...}
    finally(onFinally) {
        return this.then(onFinally, onFinally);
    }
}

resolve

promise的静态方法resolve,默认执行resolve成功

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

reject

promise的静态方法reject,默认执行reject失败

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

all / allSettled

promise的静态方法all/allSettled,传参为数组

  • all 只有全为resolve时才会成功,有一个为reject直接reject
  • allSettled 不管成功失败都会走resolve
  • 返回值都是数组,且顺序一致
static all(promises) {
    return new MyPromise((resolve, reject) => {
      MyPromise.#createRangeGenerator("all", promises, resolve, reject);
    });
  }
static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      MyPromise.#createRangeGenerator("allSettled", promises, resolve, reject);
    });
  }
 // 生成器自动化执行all/allSettled
// 采用生成器是模拟,当executor中都是不同时间返回值,插入数组的值就会按照快慢返回而错乱
  static #createRangeGenerator(type, promises, resolve, reject) {
    const result = [];
    function* generator() {
      yield* promises;
    }
    function execGeneratorFn(generatorFn) {
      const genFn = generatorFn();
      (function exec() {
        const res = genFn.next();
        if (res.done) return res.value;
        if (type === "all") {
          res.value.then((value) => {
            result.push(value);
            if (result.length === promises.length) resolve(result);
            exec();
          }, reject);
        }
        if (type === "allSettled") {
          res.value.then(
            (value) => {
              result.push({ status: MyPromise.#PROMISE_STATUS_FULFILLED, value });
              if (result.length === promises.length) resolve(result);
              exec();
            },
            (reason) => {
              result.push({ status: MyPromise.#PROMISE_STATUS_REJECTED, reason });
              if (result.length === promises.length) resolve(result);
              exec();
            }
          );
        }
      })();
    }
    execGeneratorFn(generator);
    return result;
  }

race / any

promise的静态方法rece/any,传参为数组

  • rece 竞速传入多个promise,无论成功失败,只返回最快的一个
  • any 只返回成功最快的一个,当全部为错误时,返回AggregateError报错
static race(promises){
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise =>{
        promise.then(resolve,reject)
      })
    });
  }
  static any(promises){
    return new MyPromise((resolve, reject) => {
      const result = []
      promises.forEach(promise =>{
        promise.then(resolve,reason=>{
          result.push(reason)
          if (result.length === promises.length){
            reject(new AggregateError(result,"All promises were rejected"))
          }
        })
      })
    });
  }

总结 :

class MyPromise {
  static #PROMISE_STATUS_PENDING = "pending";
  static #PROMISE_STATUS_FULFILLED = "fulfilled";
  static #PROMISE_STATUS_REJECTED = "rejected";

  constructor(executor) {
    this.status = MyPromise.#PROMISE_STATUS_PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledFns = [];
    this.onRejectedFns = [];
    const resolve = (value) => {
      if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== MyPromise.#PROMISE_STATUS_PENDING) return;
          this.status = MyPromise.#PROMISE_STATUS_FULFILLED;
          this.value = value;
          this.onFulfilledFns.forEach((fn) => fn(this.value));
        });
      }
    };
    const reject = (reason) => {
      if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== MyPromise.#PROMISE_STATUS_PENDING) return;
          this.status = MyPromise.#PROMISE_STATUS_REJECTED;
          this.reason = reason;
          this.onRejectedFns.forEach((fn) => fn(this.reason));
        });
      }
    };
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFulfilled, onRejected) {
    const defaultOnFulfilled = (value) => value;
    const defaultOnRejected = (error) => {
      throw error;
    };
    onFulfilled ||= defaultOnFulfilled;
    onRejected ||= defaultOnRejected;
    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.#PROMISE_STATUS_FULFILLED) {
        MyPromise.#catchFunctionExecutor(onFulfilled, this.value, resolve, reject);
      }
      if (this.status === MyPromise.#PROMISE_STATUS_REJECTED) {
        MyPromise.#catchFunctionExecutor(onRejected, this.reason, resolve, reject);
      }
      if (this.status === MyPromise.#PROMISE_STATUS_PENDING) {
        this.onFulfilledFns.push(() => {
          MyPromise.#catchFunctionExecutor(onFulfilled, this.value, resolve, reject);
        });
        this.onRejectedFns.push(() => {
          MyPromise.#catchFunctionExecutor(onRejected, this.reason, resolve, reject);
        });
      }
    });
  }

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

  finally(onFinally) {
    return 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) => {
      MyPromise.#createRangeGenerator("all", promises, resolve, reject);
    });
  }

  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      MyPromise.#createRangeGenerator("allSettled", promises, resolve, reject);
    });
  }

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

  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const result = [];
      promises.forEach((promise) => {
        promise.then(resolve, (reason) => {
          result.push(reason);
          if (result.length === promises.length) {
            reject(new AggregateError(result, "All promises were rejected"));
          }
        });
      });
    });
  }

  // 生成器自动化执行all/allSettled
  static #createRangeGenerator(type, promises, resolve, reject) {
    const result = [];
    function* generator() {
      yield* promises;
    }
    function execGeneratorFn(generatorFn) {
      const genFn = generatorFn();
      (function exec() {
        const res = genFn.next();
        if (res.done) return res.value;
        if (type === "all") {
          res.value.then((value) => {
            result.push(value);
            if (result.length === promises.length) resolve(result);
            exec();
          }, reject);
        }
        if (type === "allSettled") {
          res.value.then(
            (value) => {
              result.push({ status: MyPromise.#PROMISE_STATUS_FULFILLED, value });
              if (result.length === promises.length) resolve(result);
              exec();
            },
            (reason) => {
              result.push({ status: MyPromise.#PROMISE_STATUS_REJECTED, reason });
              if (result.length === promises.length) resolve(result);
              exec();
            }
          );
        }
      })();
    }
    execGeneratorFn(generator);
    return result;
  }

  // 错误捕获执行器
  static #catchFunctionExecutor(method, value, resolve, reject) {
    try {
      const result = method(value);
      resolve(result);
    } catch (e) {
      reject(e);
    }
  }
}

文章内容较长,如果表达有误在所难免,欢迎交流指出.