总结手写Promise

Promise

Promise对象代表一个一步操作,共有三种功能状态:

  1. pending进行中;
  2. fulfilled已成功;
  3. rejected已失败;

pending为默认状态,执行的结果只能是fulfilled和rejected,并且状态是不可逆的。
Promise只以第一次为准,第一成功就永久fulfilled,第一次失败就永久rejected
Promise中有throw的话,就等于是执行了reject();
resolve可以把状态改为fulfilled,reject或者throw可以把状态修改为rejected;
处于pending状态的Promise,then函数不会被调用;
实例化Promise对象时候必须传递一个函数,这个函数包含两个参数:resolvereject

代码如下

// Promise 有三种状态
class MyPromise {
  // pending/fulfilled/rejected, 初始是pending,只能变为fulfilled或者rejected并且不可逆
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";
  constructor(func) {
    // Promise的结果
    this.result = null;
    // Promise的状态
    this.status = MyPromise.PENDING;
    // 异步处理的回调函数
    this.fulfilledCallBack = [];
    this.rejectedCallBack = [];
    try {
      // 防止this丢失
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
  // 成功的回调
  resolve(result) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED;
      this.result = result;
      // 把存的异步回调拿出来执行
      this.fulfilledCallBack.forEach((cb) => cb(result));
    }
  }
  // 失败的回调
  reject(reason) {
    // 同上
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED;
      this.result = reason;
      this.rejectedCallBack.forEach((cb) => cb(reason));
    }
  }
  // then 方法,接受两个回调函数
  then(onFulfilled, onRejected) {
    // 判断是否是函数
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };
    // 成功就执行成功的,失败就执行失败的,还是pending就先收集起来
    if (this.status === MyPromise.PENDING) {
      this.fulfilledCallBack.push(() => {
        setTimeout(() => {
          onFulfilled(this.result);
        });
      });
      this.rejectedCallBack.push(() => {
        setTimeout(() => {
          onRejected(this.result);
        });
      });
    }
    if (this.status === MyPromise.FULFILLED) {
      // 回调函数是异步执行的
      setTimeout(() => {
        onFulfilled(this.result);
      });
    }
    if (this.status === MyPromise.REJECTED) {
      // 回调函数是异步执行的
      setTimeout(() => {
        onRejected(this.result);
      });
    }
  }
}
// 测试代码
/** 测试代码start **/
console.log(1);
let promise1 = new MyPromise((resolve, reject) => {
  console.log(2);
  setTimeout(() => {
    console.log("A", promise1.status);
    resolve("这次一定");
    console.log("B", promise1.status);
    console.log(4);
  });
});
promise1.then(
  (result) => {
    console.log("C", promise1.status);
    console.log("fulfilled:", result);
  },
  (reason) => {
    console.log("D", promise1.status);
    console.log("rejected:", reason);
  }
);

/** 测试代码stop **/

then链式调用

then方法需要返回一个新的promise对象才能支持链式调用;
根据第一个promise处理的结果来处理下一个promise的操作;
第一个promise的处理结果有三种情况:

  1. 是一个普通值;
  2. 还是一个promise对象;
  3. 是一个对象或者方法,有可能是一个thenable对象;
    如果是一个普通值,就直接resolve;
    如果是一个promise对象,就调用对应的then方法继续处理;
    如果是一个对象或者方法,就判断是否是一个thenable对象,thenable对象需要特殊处理,需要添加一个开关判断是否正在执行,因为then方法有可能被调用多次,如果是一个普通对象或者函数,直接resolve;

代码如下

// 手写promise then函数的调用
class MyPromise {
  // pending/fulfilled/rejected, 初始是pending,只能变为fulfilled或者rejected并且不可逆
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";
  constructor(func) {
    // Promise的结果
    this.result = null;
    // Promise的状态
    this.status = MyPromise.PENDING;
    // 异步处理的回调函数
    this.fulfilledCallBack = [];
    this.rejectedCallBack = [];
    try {
      // 防止this丢失
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
  // 成功的回调
  resolve(result) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED;
      this.result = result;
      // 把存的异步回调拿出来执行
      this.fulfilledCallBack.forEach((cb) => cb(result));
    }
  }
  // 失败的回调
  reject(reason) {
    // 同上
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED;
      this.result = reason;
      this.rejectedCallBack.forEach((cb) => cb(reason));
    }
  }

  then(onFulfilled, onRejected) {
    // 链式调用需要返回一个行的promise
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.PENDING) {
        this.fulfilledCallBack.push(() => {
          setTimeout(() => {
            try {
              if (typeof onFulfilled !== "function") {
                resolve(this.result);
              } else {
                let x = onFulfilled(this.result);
                resolvePromise(promise2, x, resolve, reject);
              }
            } catch (error) {
              reject(error);
            }
          });
        });
        this.rejectedCallBack.push(() => {
          setTimeout(() => {
            try {
              if (typeof onRejected === "function") {
                reject(this.result);
              } else {
                let x = onRejected(this.result);
                resolvePromise(promise2, x, resolve, reject);
              }
            } catch (error) {
              reject(error);
            }
          });
        });
      }
      // 成功和失败的时候都需要处理 promise
      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          // 获取处理的返回值
          // 如果获取失败,直接就拒绝掉
          try {
            // 判读但onFullfilled是否是一个函数,不是函数直接返回结果
            if (typeof onFulfilled !== "function") {
              resolve(this.result);
            } else {
              let x = onFulfilled(this.result);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (error) {
            reject(error);
          }
        });
      }
      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          try {
            // 判断是否是函数
            if (typeof onRejected === "function") {
              let x = onRejected(this.result);
              resolvePromise(promise2, x, resolve, reject);
            } else {
              reject(this.result);
            }
          } catch (error) {
            reject(error);
          }
        });
      }
    });
    return promise2;
  }
}

/**
 * 在新的promise中处理resolve和reject
 * @param {*} promise2 返回新的promise对象
 * @param {*} x promise1处理的结果
 * @param {*} resolve 新的promise的resolve方法
 * @param {*} reject 新的promise的reject方法
 *
 */

function resolvePromise(promise2, x, resolve, reject) {
  // 如果返回的promise和当前的promise相同,就报错
  if (promise2 === x) {
    return reject(new TypeError("循环引用了 "));
  }
  // 处理不同值
  // 1.是一个promise
  // 2.是一个对象或者函数,有thenable方法则执行then,否则直接resolve
  // 3.一个普通值
  if (x instanceof promise2) {
    // 是一个promise的实例,执行then 方法
    x.then((y) => {
      resolvePromise(promise2, y, resolve, reject),
        (reason) => {
          reject(reason);
        };
    });
  } else if (x !== null && (typeof x === "object" || typeof x === "function")) {
    let then;
    try {
      then = x.then;
    } catch (error) {
      reject(error);
    }
    if (typeof then === "function") {
      let called = false;
      try {
        then.call(x, (y) => {
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }),
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          };
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      resolve(x);
    }
  } else {
    // 普通值直接返回
    return resolve(x);
  }
}

// 测试代码
/** 测试代码start **/
console.log(1);
let promise1 = new MyPromise((resolve, reject) => {
  console.log(2);
  setTimeout(() => {
    console.log("A", promise1.status);
    resolve("这次一定");
    console.log("B", promise1.status);
    console.log(4);
  });
});
promise1.then(
  (result) => {
    console.log("C", promise1.status);
    console.log("fulfilled:", result);
  },
  (reason) => {
    console.log("D", promise1.status);
    console.log("rejected:", reason);
  }
);

/** 测试代码stop **/

其他方法

resolve

resolve方法是将一个值编程一个promise对象。
传入的值有这三种判断:

  1. 如果是一个promise对象直接返回;
  2. 如果是一个thenable对象,就是带有then方法的对象,会跟随这个thenable对象的then方法返回一个新的promise;
  3. 否则就返回一个新的promise并且resolve这个值
    代码如下
MyPromise.resolve = function (value) {
  //1.是一个promise直接返回
  if (value instanceof MyPromise) {
    return value;
  }
  // 是一个thenable。跟随这个thenable
  if (typeof value === "object" && value !== null && "then" in value) {
    return new MyPromise((resolve, reject) => {
      value.then(resolve, reject);
    });
  }
  // 如果只是普通值,直接reso
  return new MyPromise((resolve, reject) => {
    resolve(value);
  });
};

reject

reject 方法是返回一个带有拒绝原因的对象;
原理就是返回一个新的promise然后执行reject方法,把传入原因reject出去;
代码如下

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

catch

catch 方法其实就是 .then(undefined,onRejected)的简写;
代码如下

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

finally

finally方法,不管promise的状态如何,都会执行内部其实就是执行then方法,并把传入的参数作为then方法的入参;
代码如下

finally(callback){
	return this.then(callback,callback);
}

all

all 方法接受一个promise数组,如果数组中包含普通值,不会做处理原封不动的返回;
all 方法会等待所有任务完成,或者遇到第一个失败的任务就返回,并且返回一个新的promise实例,存放所有成功结果的数组,失败则抛出第一个失败的原因;
代码如下

  // 接受一个promise数组
  static all(promises) {
    // 返回一个新的promise实例
    return new MyPromise((resolve, reject) => {
      if (Array.isArray(promises)) {
        // 存放所有的成功的结果
        const result = [];
        // 计数器
        let count = 0;
        // 如果传入的是空数组
        if (promises.length === 0) {
          // 直接把原内容返回
          resolve(promises);
        }
        promises.forEach((item, index) => {
          MyPromise.resolve(item).then(
            (value) => {
              count++;
              result[index] = value;
              count === promises.length && resolve(result);
            },
            (reason) => {
              // 如果第一个就报错,直接结束
              reject(reason);
            }
          );
        });
      } else {
        throw new TypeError("传入的参数必须是一个数组");
      }
    });
  }

allSettled

allSettled方法接受一个promise数组,返回一个新的promise对象,会处理每一个promise,给出一个数组对象,每个对象表示对应的promise结果;
allSettled适合用于有多个不相互依赖的异步任务中,或者你想要知道每一个promise的结果,而all 更适合彼此有相互依赖或者其中一个失败就立即结束的情况;

对于每个结果对象,都有一个status字符串,如果成功就是fulfilled,对应的值是value,如果失败就是rejected,对应的值是reason;
代码如下


  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      // 判断promises是否是一个数组
      if (Array.isArray(promises)) {
        const result = [];
        let count = 0;
        if (promises.length === 0) {
          resolve(promises);
        }
        promises.forEach((item, index) => {
          MyPromise.resolve(item).then(
            (value) => {
              count++;
              result[index] = {
                status: MyPromise.FULFILLED,
                value,
              };
              count === promises.length && resolve(result);
            },
            (reason) => {
              count++;
              result[index] = {
                status: MyPromise.REJECTED,
                value: reason,
              };
              count === promises.length && resolve(result);
            }
          );
        });
      } else {
        throw new TypeError("传入的参数必须是一个数组");
      }
    });
  }

any

any和all是相反的;
any接受一个promise数组,只要其中有一个promise成功,就返回那个成功promise;
如果都失败了,就返回一个失败promise;
如果参数是一个空数组,返回一个失败的promise;
如果参数中不包含promise,将这些数据转换成一个promise然后返回一个成功promise;
代码如下

 static any(promises) {
    // 返回一个新的promise
    return new MyPromise((resolve, reject) => {
      // 判断是否是一个数组
      if (Array.isArray(promises)) {
        // 收集错误
        const errors = [];
        // 计数器
        let count = 0;
        // 如果传入的是空数组
        if (promises.length === 0) {
          // 直接把原内容返回
          reject(new Error("promises为空"));
        }
        promises.forEach((item, index) => {
          // 把非promise转成promise
          MyPromise.resolve(item).then(
            (value) => {
              // 有一个成功直接resolve
              resolve(value);
            },
            (error) => {
              count++;
              errors[index] = error;
              count === promises.length && reject(new Error(errors));
            }
          );
        });
      } else {
        reject(new TypeError("传入的参数必须是一个数组"));
      }
    });
  }

race

返回第一个执行成功的promise;
也就是接受第一个promise数组,返回第一个成功的promise;
如果是一个空数组,返回一个永远等待的promise;

代码如下

static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (Array.isArray(promises)) {
        if (promises.length > 0) {
          promises.forEach((item) => {
            // 第一个处理完成的返回
            MyPromise.resolve(item).then(resolve, reject);
          });
        }
      } else {
        reject(new TypeError("promises必须是一个数组"));
      }
    });
  }
  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值