保姆级教程,一次性搞懂手写Promise的全过程,彻底搞懂Promise原理

本文详细介绍了Promise在ES6中的实现,包括构造函数、实例方法(then,catch,finally)和静态方法(resolve,reject,race,all),以及如何解决异步编程中的问题和实现链式操作。
摘要由CSDN通过智能技术生成

         Promise是一个有状态的构造函数,出自ES6,主要用于实现异步编程,API请求等。它的出现避免了以往的回调地狱的问题,使得代码更加清晰,易于维护。该构造函数主要有以下几部分组成,分别是:构造器,实例方法:then,catch,finally。静态方法:resolve,reject,race,all等。

本文将从以下步骤分别实现上述功能:

1.构造函数

定义类 -> 添加构造函数-> 设置状态及原因->定义resolve/reject-> 设置状态不可逆->执行回调函数

代码如下:

  /*

      定义3个变量

      pending:等待;fulfilled:执行成功;rejected:执行失败

    */

    const PENDING = "pending";

    const FULFILLED = "fulfilled";

    const REJECTED = "rejected";

    class MYPromise {

      // 定义变量保存状态

      status = PENDING;

      // 定义变量用来存储原因

      result = undefined;

      // 保存回调函数

      #handlers = [];

      constructor(func) {

        const resolve = (result) => {

          // 设置状态不可逆

          if (this.status == PENDING) {

            this.status = FULFILLED;

            this.result = result;

            // 调用成功回调

            this.#handlers.forEach(({ onFulfilled }) => {

              onFulfilled(this.result);

            });

          }

        };

        const reject = (result) => {

          // 设置状态不可逆

          if (this.status == PENDING) {

            this.status = REJECTED;

            this.result = result;

            // 调用失败回调

            this.#handlers.forEach(({ onRejected }) => {

              onRejected(this.result);

            });

          }

        };

        try {

          func(resolve, reject);

        } catch (error) {

          reject(error);

        }

      }

    }

运行的结果如下:Promise的状态变更时不可逆的,只有pending->fulfilled,pending->rejected;

2.实现实例方法then

实现思路:添加实例方法->进行参数判断->执行成功回调->执行失败回调->处理异步和多次调用的问题。

代码如下:

then(onFulfilled, onRejected) {

        onFulfilled = typeof onFulfilled == "function" ? onFulfilled : (x) => x;

        onRejected =

          typeof onRejected == "function"

            ? onRejected

            : (x) => {

                throw x;

              };

        const p2 = new MYPromise((resolve, reject) => {

          // 执行成功回调

          if (this.status == FULFILLED) {

            handlerSyncTask(() => {

              try {

                const x = onFulfilled(this.result);

                resolvePromise(x, p2, resolve, reject);

              } catch (err) {

                reject(err);

              }

            });

          } else if (this.status == REJECTED) {

            handlerSyncTask(() => {

              try {

                const x = onRejected(this.result);

                resolvePromise(x, p2, resolve, reject);

              } catch (err) {

                reject(err);

              }

            });

            // 异步时,保存回调函数

          } else if (this.status == PENDING) {

            this.#handlers.push({

              onFulfilled: () => {

                handlerSyncTask(() => {

                  try {

                    const x = onFulfilled(this.result);

                    resolvePromise(x, p2, resolve, reject);

                  } catch (error) {

                    reject(error);

                  }

                });

              },

              onRejected: () => {

                handlerSyncTask(() => {

                  try {

                    const x = onRejected(this.result);

                    resolvePromise(x, p2, resolve, reject);

                  } catch (error) {

                    reject(error);

                  }

                });

              },

            });

          }

        });

        return p2;

      }

运行结果如下:

2.1 执行成功的回调

2.2  执行失败的回调

2.3 处理异步的情况

在Promise中,代码的执行书序分别是:主任务 ->微任务 ->宏任务(setTimeout);当new一个Promise时,传入的回调函数为同步代码,会立即执行,而then,catch里面的为异步任务。

以下为封装的异步函数,并在then方法中进行调用:

then方法中异步任务的执行结果如下:

2.4 处理多次调用的情况

运行结果如下:

3 实现链式编程

3.1 封装函数,处理重复引用,返回值是Promise,和普通值的情况(fulfilled)

代码如下:

测试并运行结果如下:

3.11 处理返回值

3.12 返回值是Promise

3.13 处理重复引用的异常

3.2  处理rejected

代码如下:

执行结果如下:

3.3 处理pending 状态

执行结果如下:

4 实例方法catch

catch方法相当于then方法中的第二个回调函数功能。其实现代码如下:

调用catch方法,执行结果如下:

5 实例方法finally

Promise无论执行成功,或是失败,都会执行finally方法。代码如下:

代码执行结果如下:

6 静态方法resolve 

resolve可通过构造函数直接调用,代码如下:

执行代码,结果如下:

7 静态方法 reject

执行结果如下:

8 静态方法 race

race方法用于处理多个异步任务的情况,入参是一个可迭代的对象。等待期中某一个任务执行完毕并返回。其代码如下:

测试代码执行结果如下:

9 静态方法 all

all方法也是用于处理多个异步任务的情况,与race不同的是,all方法会等到所有异步任务执行完毕并返回结果,当有一个任务执行异常,会直接返回异常的任务.代码如下:

代码运行结果如下:

附录:

完成代码如下:

 // 封装异步函数,在then方法中进行回调

    function handlerSyncTask(callback) {

      if (typeof queueMicrotask == "function") {

        queueMicrotask(callback);

      } else if (typeof MutationObserver == "function") {

        const obs = new MutationObserver(callback);

        const divNode = document.createElement("div");

        obs.observe(divNode, { childList: true });

        divNode.innerText("synctask");

      } else {

        setTimeout(callback, 0);

      }

    }

    // 封装方法-判断返回值类型并进行处理

    function resolvePromise(x, p2, resolve, reject) {

      if (x === p2) {

        throw new TypeError("chaining cycle detected for promise");

      }

      if (x instanceof MYPromise) {

        x.then(

          (res) => resolve(res),

          (err) => reject(err)

        );

      } else {

        resolve(x);

      }

    }

    /*

      定义3个变量

      pending:等待;fulfilled:执行成功;rejected:执行失败

    */

    const PENDING = "pending";

    const FULFILLED = "fulfilled";

    const REJECTED = "rejected";

    class MYPromise {

      // 定义变量保存状态

      status = PENDING;

      // 定义变量用来存储原因

      result = undefined;

      // 保存回调函数

      #handlers = [];

      constructor(func) {

        const resolve = (result) => {

          // 设置状态不可逆

          if (this.status == PENDING) {

            this.status = FULFILLED;

            this.result = result;

            // 调用成功回调

            this.#handlers.forEach(({ onFulfilled }) => {

              onFulfilled(this.result);

            });

          }

        };

        const reject = (result) => {

          // 设置状态不可逆

          if (this.status == PENDING) {

            this.status = REJECTED;

            this.result = result;

            // 调用失败回调

            this.#handlers.forEach(({ onRejected }) => {

              onRejected(this.result);

            });

          }

        };

        try {

          func(resolve, reject);

        } catch (error) {

          reject(error);

        }

      }

      then(onFulfilled, onRejected) {

        onFulfilled = typeof onFulfilled == "function" ? onFulfilled : (x) => x;

        onRejected =

          typeof onRejected == "function"

            ? onRejected

            : (x) => {

                throw x;

              };

        const p2 = new MYPromise((resolve, reject) => {

          // 执行成功回调

          if (this.status == FULFILLED) {

            handlerSyncTask(() => {

              try {

                const x = onFulfilled(this.result);

                resolvePromise(x, p2, resolve, reject);

              } catch (err) {

                reject(err);

              }

            });

          } else if (this.status == REJECTED) {

            handlerSyncTask(() => {

              try {

                const x = onRejected(this.result);

                resolvePromise(x, p2, resolve, reject);

              } catch (err) {

                reject(err);

              }

            });

            // 异步时,保存回调函数

          } else if (this.status == PENDING) {

            this.#handlers.push({

              onFulfilled: () => {

                handlerSyncTask(() => {

                  try {

                    const x = onFulfilled(this.result);

                    resolvePromise(x, p2, resolve, reject);

                  } catch (error) {

                    reject(error);

                  }

                });

              },

              onRejected: () => {

                handlerSyncTask(() => {

                  try {

                    const x = onRejected(this.result);

                    resolvePromise(x, p2, resolve, reject);

                  } catch (error) {

                    reject(error);

                  }

                });

              },

            });

          }

        });

        return p2;

      }

      // catch方法

      catch(onrejected) {

        return this.then(undefined, onrejected);

      }

      // finally 方法

      finally(onfinally) {

        return this.then(onfinally, onfinally);

      }

      /*

        静态方法:resolve

      */

      static resolve(value) {

        if (value instanceof MYPromise) {

          return value;

        }

        return new MYPromise((resolve, reject) => {

          resolve(value);

        });

      }

      /*

        静态方法:reject

      */

      static reject(value) {

        return new MYPromise((undefined, reject) => {

          reject(value);

        });

      }

      /*

        静态方法:race

      */

      static race(promise) {

        return new MYPromise((resolve, reject) => {

          if (!Array.isArray(promise)) {

            return reject(new TypeError("arguments is not iterable"));

          }

          promise.forEach((p) => {

            MYPromise.resolve(p).then(

              (res) => resolve(res),

              (err) => reject(err)

            );

          });

        });

      }

      /*

         静态方法:all,获取所有的执行结果

      */

      static all(promise) {

        return new MYPromise((resolve, reject) => {

          if (!Array.isArray(promise)) {

            return reject(new TypeError("argument is not iterable"));

          }

          promise.length == 0 && resolve(promise);

          let results = [];

          let count = 0;

          promise.forEach((p, index) => {

            MYPromise.resolve(p).then(

              (res) => {

                results[index] = res;

                count++;

                count === promise.length && resolve(results);

              },

              (err) => {

                reject(err);

              }

            );

          });

        });

      }

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值