面试 - 实现最全 promise

const { reject } = require("lodash");

//模拟promise\
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  //promise是个类,传入一个执行器并立即执行
  constructor(fn) {
    try {
      fn(this.resolve, this.reject);
    } catch (error) {
      //当抛出错误时,then的reject能捕捉到
      this.reject(error);
    }
  }
  //不同实例,状态、resolve/reject、value/reason都不同,所以属性用表达式写在实例上
  status = PENDING;
  value = undefined;
  reason = undefined;
  fulfilledCallback = []; //数组能 同时存储多个回调函数
  rejectedCallback = [];

  resolve = (value) => {
    //箭头函数保证this指向实例
    if (this.status !== PENDING) return; //状态一旦确定就不能改变
    this.status = FULFILLED;
    this.value = value;
    while (this.fulfilledCallback.length) {
      this.fulfilledCallback.shift()();
    }
  };
  reject = (reason) => {
    if (this.status !== PENDING) return; //状态一旦确定就不能改变
    this.status = REJECTED;
    this.reason = reason;
    while (this.rejectedCallback.length) {
      this.rejectedCallback.shift()();
    }
  };
  //then是原型上的
  then(onFulfilled, onRejected) {
    //如果没有传参,需要补上
    onFulfilled = onFulfilled ? onFulfilled : (value) => value;
    onRejected = onRejected
      ? onRejected
      : (reason) => {
          // 用throw的原因:then的方法里面,调用reject的地方写在了catch里;
          throw reason;
        };

    //函数作参数]
    //若异步时多个then被调用:要将回调函数用数组存储起来
    //then链式调用:返回promise对象,且return出去的值作为新promise的resolve的值
    let newPromise = new MyPromise((resolve, reject) => {
      //立即执行函数
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            //捕获then回调里抛出的错误
            const res = onFulfilled(this.value); //把return出来的值传给了resolve,then的回调就拿到了
            //1.要判断是否是循环调用res === newPromis就是循环调用
            //2、res是普通值(直接调用resolve) or promise对象(判断promise返回值是成功(调用resolve)还是失败(调用 reject))
            handleRes(newPromise, res, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0); //目的:异步才可以拿到newPromise
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            //捕获then回调里抛出的错误
            const res = onRejected(this.reason); //把return出来的值传给了resolve,then的回调就拿到了
            //1.要判断是否是循环调用res === newPromis就是循环调用
            //2、res是普通值(直接调用resolve) or promise对象(判断promise返回值是成功(调用resolve)还是失败(调用 reject))
            handleRes(newPromise, res, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0); //目的:异步才可以拿到newPromise
      }
      // 异步情况,status仍是pending,那就先将将传入的参数存起来,等待status的改变,
      if (this.status === PENDING) {
        this.fulfilledCallback.push(() => {
          setTimeout(() => {
            try {
              //捕获then回调里抛出的错误
              const res = onFulfilled(this.value); //把return出来的值传给了resolve,then的回调就拿到了
              //1.要判断是否是循环调用res === newPromis就是循环调用
              //2、res是普通值(直接调用resolve) or promise对象(判断promise返回值是成功(调用resolve)还是失败(调用 reject))
              handleRes(newPromise, res, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0); //目的:异步才可以拿到newPromise
        });
        this.rejectedCallback.push(() => {
          setTimeout(() => {
            try {
              //捕获then回调里抛出的错误
              const res = onRejected(this.reason); //把return出来的值传给了resolve,then的回调就拿到了
              //1.要判断是否是循环调用res === newPromis就是循环调用
              //2、res是普通值(直接调用resolve) or promise对象(判断promise返回值是成功(调用resolve)还是失败(调用 reject))
              handleRes(newPromise, res, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0); //目的:异步才可以拿到newPromise
        });
      }
    });
    return newPromise;
  }
  //catch返回promise
  catch(callback) {
    return this.then(undefined, callback);
  }
  //finally无论失败还是成功都会走一次,返回一个promise可以在.then里拿到结果
  //如果finally的回调函数有返回值(普通值(转成promise对象)/promise对象(等待执行完成返回value))用到rsolve,
  finally(callback) {
    //无论失败还是成功都会走
    return this.then(
      //finally返回promise,所以可以直接返回this.then
      (value) => {
        return MyPromise.resolve(callback()).then(() => value); //后面的then需要拿到值
      },
      (reason) => {
        return MyPromise.resolve(callback()).then(() => {
          throw reason;
        }); //后面的then需要拿到值
      }
    );
  }
  //Promise.all([]),all方法是用类调用的,所以是一个静态方法;返回值是一个promise
  //数组里面如果是普通值,就放到结果数组中;如果是promise对象,就先去执行promise对象,将执行结果放到结果数组中
  static all(arr) {
    let resArr = []; //结果数组
    let length = 0; //因为可能有的promise的立即执行函数是异步的,需要等待
    return MyPromise((resolve, reject) => {
      function addResArr(index, res) {
        //需要保证顺序
        resArr[index] = res;
        length++;
        if (length === arr.length) {
          resolve(resArr);
        }
      }
      for (let index = 0; index < arr.length; index++) {
        //判断每一项是否是普通值
        if (arr[index] instanceof MyPromise) {
          arr[index].then(
            (res) => {
              addResArr(index, res);
            },
            (reason) => {
              reject(reason);
            }
          );
        } else {
          addResArr(index, arr[index]);
        }
      }
    });
  }
  //Promise.resolve(10);resolve方法接收的参数如果是普通值,会返回一个promise,并且结果为普通值;如果为promise对象,会将这个传入的普通对象返回;
  static resolve(data) {
    // 判断传入值是普通值还是promise
    if (data instanceof MyPromise) {
      return data;
    } else {
      return new MyPromise((resolve, reject) => resolve(data));
    }
  }
}
const handleRes = function (newPromise, res, resolve, rejct) {
  if (newPromise === res) {
    return reject("TypeError: Chaining cycle detected for promise #<Promise>");
  }
  if (res instanceof MyPromise) {
    //res是promise对象
    //res.then((value)=>{resolve(value),(reason)=>{reject(reason)}});
    res.then(resolve, rejct);
  } else {
    resolve(res);
  }
};

//测试
const resPromise = new MyPromise((resolve, reject) => {
  resolve("干你丫的小日本儿");
});
const promise = new MyPromise((resolve, reject) => {
  //   setTimeout(() => {
  //     resolve("成功了");
  //   }, 5000);
  //   resolve("成功");
  reject("失败");
  //   throw new Error("promise error"); //throw可以抛出任何类型的值,throw语句的作用是手动中断程序执行,抛出一个错误。
});

// 多次调用
promise.then(
  (res) => {
    console.log(1, "res", res);
  },
  (reason) => {
    console.log(2, "reason", reason.message);
  }
);
promise.then((res) => {
  console.log(3, "res", res);
});

// 链式调用
promise
  .then(
    (res) => {
      console.log(11, "res", res);
      return "中国必胜";
      // return resPromise;
      // throw new Error("then error");
    },
    (error) => {
      console.log(22, error);
      return 1000;
    }
  )
  .then(
    (r) => {
      console.log(33, "--r--", r);
    },
    (reason) => {
      console.log(44, "reason", reason.message);
    }
  );

/**
 * 什么是promise的循环调用
 * then return出去的promise对象是他自身生成的新的promise对象
 */
// const promise1 = new Promise((resolve, reject) => {
//   resolve(100);
// });
// const promise2 = promise1.then((res) => {
//   return promise2; //自己返回了自己,导致陷入循环
// });
// promise2.then(
//   () => {},
//   (reason) => {
//     console.log("-----循环-----", reason);
//   }
// );

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值