手写Promise then/catch/resolve/reject all/allSetteld

原生

    <script>
      const promise = new Promise((resolve, reject) => {
        resolve();
        // reject();
      });

      console.log(promise);
    </script>

//Promise是一个构造函数
//参数为一个函数,且同步自调用了(这里称它为executor)
//executor中传入了两个函数,分别是resolve和reject,用来改变promise的状态
//promise的初始状态为pending
//promise的状态只能修改一次

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MyPromise.prototype

实现resolve/reject

(function (w) {
  function MyPromise(executor) {
    // promise对象就是this,这是因为new关键字作用
    const that = this;
    /* 
        初始化promise对象是pending状态
        _开头的属性是私有属性,外界不允许操作
    */
    that._status = "pending";

    // resolve函数将promise对象状态改成resolved
    function resolve() {
      // 让promise对象状态只能修改一次
      if (that._status !== "pending") return;
      // 如果不用that,这里的this指向是有问题的
      that._status = "resolved";
    }

    // reject函数将promise对象状态改成rejected
    function reject() {
      if (that._status !== "pending") return;
      that._status = "rejected";
    }
    // 同步调用
    executor(resolve, reject);
  }
  w.MyPromise = MyPromise;
})(window);

  • html
  <body>
    <script src="./01.promise.js"></script>
    <script>
      const promise = new MyPromise((resolve, reject) => {
        resolve();
        // reject()
      });
      console.log(promise);
    </script>
  </body>

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

实现then方法–基础

promise.then(
(value) => { },
(reason) => { }
)
1.then方法是promise实例对象使用的,所以定义在原型上
2.then方法是同步执行的
3.第一个参数是成功的回调,第二个参数是失败的回调
4.回调中可以接收到promise的结果值

  • 当原型添加了then方法时,会将onResolve和onReject通过this传到promise实例对象身上
  • 而在MyPromise构造函数中,通过that(这里替换了this,也是指向promsie实例对象)拿到这两个方法,在resolve和reject中调用
  • onResolve和onReject都是异步函数
(function (w) {
  function MyPromise(executor) {
    const that = this;
    that._status = "pending";
    // 用来存储成功/失败回调函数的容器
    that._callbacks = {};

    function resolve(value) {
      if (that._status !== "pending") return;
      that._status = "resolved";
      // 触发和调用onResolved函数,切记这里要异步去调用,因为代码同步执行的,这个时候原型上还没有添加这些方法
      setTimeout(() => {
        // that._callbacks.onResolved && that._callbacks.onResolved(value);

        // 这个和上面的写法一样,但是是ES11的语法,2020年  新的运算符?.可选链
        that._callbacks.onResolved?.(value);
      }, 0);
    }
    function reject(error) {
      if (that._status !== "pending") return;
      that._status = "rejected";
      // 如果不用定时器,这样子也可以
      that._callbacks.onRejected && that._callbacks.onRejected(error);
    }

    executor(resolve, reject);
  }

  MyPromise.prototype.then = function (onResolved, onRejected) {
    /* 
      this指向实例对象promise
      将成功/失败回调添加到容器中(注意没有调用,只是去添加这个属性,在调用回调的时候执行)
      在Promise原型上添加then方法,方法中也是两个函数作为参数,分别是成功的回调和失败的回调
    */
    this._callbacks.onResolved = onResolved;
    this._callbacks.onRejected = onRejected;
  };
  w.MyPromise = MyPromise;
})(window);

  <body>
    <script src="./01.promise.js"></script>
    <script>
      const promise = new MyPromise((resolve, reject) => {
        resolve(123);
        // reject(777);
      });
      console.log(promise);

      promise.then(
        (value) => {
          console.log("then方法成功回调---->" + value);
        },
        (error) => {
          console.log("then方法失败回调---->" + error);
        }
      );
    </script>
  </body>

在这里插入图片描述

在这里插入图片描述

  • 没有解决异步
    在这里插入图片描述

then方法返回值/三种

  • 调用then方法需要返回一个promise对象
  • 因为promise的状态只能改变一次,所以我们需要返回一个新的promise对象
    1.当then方法没有返回值,或者有返回值但不是promise对象时,默认返回一个新的成功的promise对象
    2.当then方法返回一个promise对象需要判断是成功还是失败的peomsie对象
    3.当then方法调用时,内部报错,需要返回一个失败的peomise对象
(function (w) {
  function MyPromise(executor) {
    const that = this;
    that._status = "pending";
    // 定义promise默认返回值
    that._result = undefined;
    that._callbacks = {};

    function resolve(value) {
      if (that._status !== "pending") return;
      that._status = "resolved";
      // 修改promise的返回值
      that._result = value;
      setTimeout(() => {
        that._callbacks.onResolved?.(value);
      });
    }

    function reject(error) {
      if (that._status !== "pending") return;
      that._status = "rejected";
      // 修改promise的返回值
      that._result = error;
      setTimeout(() => {
        that._callbacks.onRejected && that._callbacks.onRejected(error);
      });
    }
    executor(resolve, reject);
  }

  MyPromise.prototype.then = function (onResolved, onRejected) {
    const that = this;
    // 调用then方法,返回一个新的promise对象,这样才能实现then方法的链式调用
    return new MyPromise((resolve, reject) => {
      // then的返回值,取决于内部函数的返回值,怎么拿到这个函数内部返回值呢?小技巧
      that._callbacks.onResolved = function (value) {
        const resolvedRES = onResolved(value);
        // 如果res的隐式原型在MyP的显示原型上,其实就是确认是peomise实例
        if (resolvedRES instanceof MyPromise) {
          resolvedRES.then(resolve, reject);
          /* 
            实际这个是这样的简写
            result.then(
              (value) => resolve(value),
              (reason) => reject(reason)
            );
           */
        } else {
          // 说明没有返回值或者返回值不是promise
          resolve(resolvedRES);
        }
      };
      // 其实和resolve返回机制一样
      this._callbacks.onRejected = function (error) {
        const rejectedRES = onRejected(error);
        if (rejectedRES instanceof MyPromise) {
          rejectedRES.then(resolve, reject);
        } else {
          resolve(rejectedRES);
        }
      };
    });
  };
  w.MyPromise = MyPromise;
})(window);

  • html
  <body>
    <script src="./02.promise.js"></script>
    <script>
      const promise = new MyPromise((resolve, reject) => {
        // resolve(123);
        reject(777);
      });
      console.log(promise);

      promise
        .then(
          (value) => {
            console.log("then方法成功回调---->" + value);
          },
          (error) => {
            return 50765
            console.log("then方法失败回调---->" + error);
            
          }
        )
        .then(
          (value) => {
            console.log("then2方法成功回调---->" + value);
          },
          (error) => {
            console.log("then2方法失败回调---->" + error);
          }
        );
    </script>
  </body>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

then方法返回值报错解决

  • 就是在上面代码加了try catch而已
(function (w) {
  function MyPromise(executor) {
    const that = this;
    that._status = "pending";
    that._result = undefined;
    that._callbacks = {};

    function resolve(value) {
      if (that._status !== "pending") return;
      that._status = "resolved";
      that._result = value;
      setTimeout(() => {
        that._callbacks.onResolved?.(value);
      });
    }

    function reject(error) {
      if (that._status !== "pending") return;
      that._status = "rejected";
      that._result = error;
      setTimeout(() => {
        that._callbacks.onRejected && that._callbacks.onRejected(error);
      });
    }
    executor(resolve, reject);
  }

  MyPromise.prototype.then = function (onResolved, onRejected) {
    const that = this;
    return new MyPromise((resolve, reject) => {
      that._callbacks.onResolved = function (value) {
        // 加入了try tach
        try {
          const resolvedRES = onResolved(value);
          if (resolvedRES instanceof MyPromise) {
            resolvedRES.then(resolve, reject);
          } else {
            resolve(resolvedRES);
          }
        } catch (error) {
          reject(error);
        }
      };
      this._callbacks.onRejected = function (error) {
        try {
          const rejectedRES = onRejected(error);
          if (rejectedRES instanceof MyPromise) {
            rejectedRES.then(resolve, reject);
          } else {
            resolve(rejectedRES);
          }
        } catch (error) {
          reject(error);
        }
      };
    });
  };
  w.MyPromise = MyPromise;
})(window);

在这里插入图片描述

实现catch

  • 借用then方法功能
  // 在then方法函数中结局catch的报错
      // // 为了then方法不传第二个函数(失败回调)服务
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (error) => {
            throw error;
          };
    //  为了catch方法不传第一个回调服务
    onResolved =
      typeof onResolved === "function" ? onResolved : (value) => value;


  // catch实际就是借用了then的方法
  MyPromise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
  };

  • 不带try catch的报错
    在这里插入图片描述
    在这里插入图片描述
  • 带try catch的报错
    在这里插入图片描述
   <body>
    <script src="./02.promise.js"></script>
    <script>
      const promise = new MyPromise((resolve, reject) => {
        resolve ();
        // reject(777);
      });
      console.log(promise);

      promise
        .then((value) => {
          console.log(11111, value);
        })
        // catch还是会执行,匹配的时候上一次是成功的,然后catch接收这个成功promise,是undefined,调用onResulved调用resolve报错
        .catch((err) => {
          console.log(22222, err);
        })
        .then((value) => {
          console.log(33333, value);
        })
        .catch((reason) => {
          console.log(4444, reason);
        });

    </script>
  </body>

  • 解决之后不会有报错
    在这里插入图片描述

MyPromise方法:

resolve

  // 给promise添加一个resolve方法
  MyPromise.resolve = function (value) {
    if (val instanceof MyPromise) {
      return value;
    }
    return new MyPromise((resolve) => resolve(value));
  };

reject

  // 给promise添加一个reject方法
  MyPromise.reject = function (reason) {
    return new MyPromise((resolve, reject) => reject(reason));
  };

all

  • 优化版
  // all方法所有成功返回成功promise,有一个失败返回失败promise,失败的值就是第一个失败的值
  MyPromise.all = function (promises) {
    // 定义一个数组,用来保存成功的promise
    const result = [];
    // 传入数组的长度
    const total = promises.length;
    // 已经完成的数量
    let completeNum = 0;
    // 调用all方法会返回一个新的promise,all方法接收一个数组
    return new MyPromise((resolve, reject) => {
      // 去遍历这个传入的数组
      promises.forEach((item, index) => {
        if (item instanceof MyPromise) {
          item.then(
            (value) => {
              // result[index] = value;
              // completeNum++;
              // if (total === completeNum) {
              //   resolve(result);
              // }
              Common(index, value);
            },
            // 这个方法是简写,完整版见下面
            reject
          );
        } else {
          // result[index] = item;
          // completeNum++;
          // if (total === completeNum) {
          //   resolve(result);
          // }
          Common(index, item);
        }
      });
      // 不能定义在forEach 否则每次都会创建这个函数
      function Common(index, value) {
        result[index] = value;
        completeNum++;
        if (total === completeNum) {
          resolve(result);
        }
      }
    });
  };

  • 基础版
  // all方法所有成功返回成功promise,有一个失败返回失败promise,失败的值就是第一个失败的值
  MyPromise.all = function (promises) {
    // 定义一个数组,用来保存成功的promise
    const result = [];
    // 传入数组的长度
    const total = promises.length;
    // 已经完成的数量
    let completeNum = 0;
    // 调用all方法会返回一个新的promise,all方法接收一个数组
    return new MyPromise((resolve, reject) => {
      // 去遍历这个传入的数组
      promises.forEach((item, index) => {
        if (item instanceof MyPromise) {
          item.then(
            (value) => {
              result[index] = value;
              completeNum++;
              if (total === completeNum) {
                resolve(result);
              }
            },
            (reason) => reject(reason)
          );
        } else {
          result[index] = item;
          completeNum++;
          if (total === completeNum) {
            resolve(result);
          }
        }
      });
    });
  };

      // 注意这里要写自定义的promise,否则不会进入判断,直接renturn这个promise到数组
      const p = new MyPromise((resolve) => resolve(777));
      // const f = new MyPromise((resolve, reject) => reject(9999));
      const res = MyPromise.all([111, 222, 333,p]);
      console.log(res)

在这里插入图片描述
在这里插入图片描述

allSetteld

  /* 
    只要里边的promise对象没有执行完成,则allSettled返回pending状态的promise对象
    只要里边的promise对象全部完成了,则allSettled返回fulfilled状态的promise对象(无论是否所有的promise都失败了)
    当所有的请求完成,allSettled的状态值就是成功,allSettled的value就是一个数组,包含了所有的方法内返回promise对象
  */
  MyPromise.allSetteld = function (promises) {
    // 调用allSetteld方法,返回一个promise
    return new MyPromise((resolve) => {
      // 声明一个数组,保存成功的值
      const result = [];
      // 得到传入数组的数量
      const total = promises.length;
      // 已经完成的数量
      let completeNum = 0;

      promises.forEach((item, index) => {
        if (item instanceof MyPromise) {
          item.then(
            (value) => {
              result[index] = {
                status: "resolved",
                value,
              };
              completeNum++;
              if (total === completeNum) {
                resolve(result);
              }
            },
            (reason) => {
              result[index] = {
                state: "rejected",
                reason,
              };
              completeNum++;
              if (total === completeNum) {
                resolve(result);
              }
            }
          );
        } else {
          result[index] = {
            state: "resolved",
            value: item,
          };
          completeNum++;
          if (total === completeNum) {
            resolve(result);
          }
        }
      });
    });
  };

      const p = new MyPromise((resolve) => {
        setTimeout(() => {  
          resolve(777);
        }, 2000);
      });
      const f = new MyPromise((resolve, reject) => reject(9999));
      const res = MyPromise.allSetteld([111, 222, 333, p, f]);
      console.log(res);

      setTimeout(()=>{
        console.log(res)
      },3000)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值