手写Promise (自定义Promise) —— Promise从入门到自定义笔记

一、自定义Promise

Promise.js文件

/**
 * 自定义Promise函数模块: ES5如何自定义模块?IIFE 匿名函数自调用;函数自调用
 */
(function(window) {
    
    
  const PENDING = "pending";
  const RESOLVED = "resolved";
  const REJECTED = "rejected";
  /**
   * Promise 构造函数 ;excutor 执行器函数 (同步执行);
   */
  function Promise(excutor) {
    
    
    // 将当前promise对象保存起来;
    const self = this;
    self.status = PENDING; // 给promsie指定status,初始为pendding;
    self.data = undefined; // 给promise指定一个存储数据的属性
    self.callbacks = []; // 每个元素的结构:{onResolved(){},onRejected(){}}
    /** 用于改变promise状态 */
    function resolve(value) {
    
    
      // 如果当前状态不是pending,直接结束;因为 状态只能改变一次,status为pending的时候,才能继续往下执行;
      if (self.status !== PENDING) return;
      // 1. status状态改为resolved
      self.status = RESOLVED;
      // 2. 保存value数据
      self.data = value;
      // 如果有待执行的callback函数,立即异步执行(需放入队列中,这里借助setTimeout)回调函数onResolved;
      if (self.callbacks.length > 0) {
    
    
        setTimeout(() => {
    
    
          // 放入队列中,执行所有成功的回调
          self.callbacks.forEach(callbacksObj => {
    
    
            callbacksObj.onResolved(value);
          });
        });
      }
    }

    function reject(reason) {
    
    
      // 如果当前状态不是pending,直接结束;因为 状态只能改变一次,status为pending的时候,才能继续往下执行;
      if (self.status !== PENDING) return;
      // 1. status状态改为rejected
      self.status = REJECTED;
      // 2. 保存value数据
      self.data = reason;
      // 如果有待执行的callback函数,立即异步执行(需放入队列中,这里借助setTimeout)回调函数onResolved;
      if (self.callbacks.length > 0) {
    
    
        setTimeout(() => {
    
    
          // 放入队列中,执行所有成功的回调
          self.callbacks.forEach(callbacksObj => {
    
    
            callbacksObj.onRejected(reason);
          });
        });
      }
    }

    // 立即同步执行excutor
    try {
    
    
      excutor(resolve, reject);
    } catch (error) {
    
    
      reject(error); // 如果执行器抛出异常,promise变为失败状态,故调用reject
    }
  }

  /**
   * Promise原型对象的方法then();
   * 指定成功或者失败的回调
   * 返回一个promise对象
   */
  Promise.prototype.then = function(onResolved, onRejected) {
    
    
    const self = this;
    // 指定回调函数的默认值,调用.then的时候,可能不执行onRejected
    onResolved = typeof onResolved === "function" ? onResolved : value => value; // 向后传递成功的value
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : reason => {
    
    
            throw reason; // 指定默认的失败的回调,将异常传下去;(实现错误/异常传透);向后传递失败的reason
          };

    // 返回一个新的promise
    return new Promise((resolve, reject) => {
    
    
      function handler(callback) {
    
    
        // 根据执行的结果,改变return的promise状态;
        /**
         * onResolved或者onRejected 的结果有三种情况:
         * 1.抛出异常,return的promise就会失败,状态为rejected状态,reason就是error
         * 2.返回一个非promise,return的promise就会成功,状态为resolved状态,value就是返回的值;
         * 3.返回一个promise,return的promise的结果就是该promise的结果;
         */

        try {
    
    
          const result = callback(self.data);
          if (result instanceof Promise) {
    
    
            // result.then(
            //   value => {
    
    
            //     resolve(value);
            //   },
            //   reason => {
    
    
            //     reject(reason);
            //   }
            // );
            result.then(resolve, reject);
          } else {
    
    
            resolve(result);
          }
        } catch (error) {
    
    
          reject(error);
        }
      }

      if (self.status === PENDING) {
    
    
        // pending,将回调函数存起来,等待被执行;并让它影响return的promise的状态;

        self.callbacks.push({
    
    
          onResolved(value) {
    
    
            // value,这个参数要不要都可
            handler(onResolved);
          },
          onRejected(reason) {
    
    
            handler(onRejected);
          }
        });
      } else if (self.status === RESOLVED) {
    
    
        // resolved,异步执行onResolved函数,并改变return的promise状态;
        setTimeout(() => {
    
    
          handler(onResolved);
        });
      } else {
    
    
        // rejected,异步执行onRejected函数
        setTimeout(() => {
    
    
          handler(onRejected);
        });
      }
    });
  };

  /**
   * Promise 原型对象的catch()方法;
   * 指定失败的回调;
   * 返回一个promise
   */
  Promise.prototype.catch = function(onRejected) {
    
    
    return this.then(undefined, onRejected);
  };

  // Promise原型链上的方法finally(onFinally) ;无论promise是fulfilled或者是rejected,都会执行指定的回调函数onFinally
 /**
   *本质上是有个then方法;且finally要在要在promise状态改变之后才执行
   * 返回promise,返回的promsie的成功与否,取决于onFinally的结果;
   * 而onFinally的执行结果,应该取决于前一个p 或者.then的执行结果;
   * 这里有个很重要的点,finally表示的是一定会执行,但并不一定是最后执行;
   * 所以在finally中,应该将p的value或者reason向后传递下去;
   */
  Promise.prototype.finally = function(onFinally) {
    
    
   onFinally = typeof onFinally === "function" ? onFinally : function() {
    
    };
    return this.then(
      value => {
    
    
        return Promise.resolve(onFinally()).then(() => value); // 向后传递成功的value (调用finally的promsie的成功的value)
      },
      reason => {
    
    
        return Promise.resolve(onFinally()).then(() => {
    
    
          // 实现异常传透;向后传递失败的reason
          throw reason;
        });
      }
    );
  };

  /**
   * Promise 函数对象的resolve方法;
   * 返回一个成功或者失败的promise
   */
  Promise.resolve = function(data) {
    
    
    /**
     * 1. 如果接收的是一般值,promise成功,value就是这个值;
     * 2. 如果结束皮的是成功的promise,则promise成功,value是该promise的value;
     * 3. 如果接收的是一个失败的promsie,则promsie失败,reason是该promsie的reason
     */
    return new Promise((resolve, reject) => {
    
    
      if (data instanceof Promise) {
    
    
        data.then(resolve, reject);
      } else {
    
    
        resolve(data);
      }
    });
  };

  /**
   * Promise 函数对象的reject方法;
   * 返回指定结果的一个失败的promise;
   */
  Promise.reject = function(reason) {
    
    
    return new Promise((resolve, reject) => {
    
    
      reject(reason);
    });
  };

  /**
   * Promise 函数对象的all(promises)方法;promises数组中的元素并不一定都是promsie,也可能只是一个普通的值,如:5
   * 返回一个promise,当所有的promise都成功的时候,该promise 才是成功状态;如果成功,返回所有成功的promise;如果失败,返回失败的reason;
   */
  Promise.all = function(promises) {
    
    
    return new Promise((resolve, reject) => {
    
    
      const values = new Array(promises.length); //  创建一个和promises长度相同的values数组;用于保存成功的value 数据;
      let count = 0; // 用来保存成功的promsie的个数
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
    
    
        // 这里将的p不一定是一个promsie,故需将其包装成一个promsie;如果它是一个promsie,再包一层也无所谓; Promise.resolve(p)
        Promise.resolve(p).then(
          value => {
    
    
            count++;
            // 把value按顺序放入values中;;将value放入values中,且这里存的顺序应和传入的promsies中的顺序一致;(数组中的元素和传入all方法中的promsies中的顺序是一样的)
            values[index] = value;
            // 所有的成功了,将return的promise改为成功;
            if (promises.length === count) {
    
    
              resolve(values);
            }
          },
          reason => {
    
    
            reject(reason);
          }
        );
      });
    });
  };

  /**
   * Promise函数对象的race方法;
   * 返回一个promise,返回最先完成的那个promise,无论他成功还是失败;
   */
  Promise.race = function(promises) {
    
    
    return new Promise((resolve, reject) => {
    
    
      // 遍历promises获取每个promise的结果;因为promise的状态只能改变一次,故,只有第一次调用才有效果;
      promises.forEach((p, index) => {
    
    
        Promise.resolve(p).then(
          value => {
    
    
            // 一旦有成功,就将return变为成功;
            resolve(value);
          },
          reason => {
    
    
            // 一旦失败,将return 变为失败
            reject(reason);
          }
        );
      });
    });
  };

  /**
   * Promise 函数对象的any(promises)方法;
   * 返回第一个成功状态的promise;如果都失败,返回 AggregateError: All promises were rejected
   */
  Promise.any = function(promises) {
    
    
    return new Promise((resolve, reject) => {
    
    
      let count = 0; // 记录失败的promsie个数
      promises.forEach((p, index) => {
    
    
        Promise.resolve(p).then(
          value => {
    
    
            resolve(value);
          },
          reason => {
    
    
            count++;
            if (count === promises.length) {
    
    
              reject("AggregateError: All promises were rejected");
            }
          }
        );
      });
    });
  };

  /**
   * Promsie 函数对象的allSettled(promises)方法;
   * 返回一个promise,当所有的promise都是已敲定状态的时候,返回一个promise,并带有一个对象数组,
   * 该对象数组是所有settled的promise的信息;
   * 否则无返回;
   */
  Promise.allSettled = function(promises) {
    
    
    return new Promise((resolve, reject) => {
    
    
      const values = new Array(promises.length); // 装所有settled的promsie
      let count = 0; // 定义已经settled的promsie的个数
      promises.forEach((p, index) => {
    
    
        Promise.resolve(p)
          .then(
            value => {
    
    
              values[index] = {
    
    
                status: "fulfilled",
                value: value
              };
            },
            reason => {
    
    
              values[index] = {
    
    
                status: "rejected",
                reason: reason
              };
            }
          )
          .then(value => {
    
    
            // promise是settled状态的时候,才会进入这个then
            count++;
            if (count === promises.length) {
    
    
              resolve(values);
            }
          });
      });
    });
  };

  // 自定义两个函数:resolveDelay和rejectDelay;
  /**
   * 返回一个promise对象,在指定时间过后,才确定promise结果
   */
  Promise.resolveDelay = function(value, time) {
    
    
    return new Promise((resolve, reject) => {
    
    
      setTimeout(() => {
    
    
        if (value instanceof Promise) {
    
    
          value.then(resolve, reject);
        } else {
    
    
          resolve(value);
        }
      }, time);
    });
  };
  // 返回一个promise对象,在指定时间过后,才失败
  Promise.rejectDelay = function(reason, time) {
    
    
    return new Promise((resolve, reject) => {
    
    
      setTimeout(() => {
    
    
        reject(reason);
      }, time);
    });
  };
  // 向外暴露Promise函数
  window.Promise = Promise;
})(window);

二、引入刚刚的Promise.js进行测试

test.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Promise</title>
  </head>
  <body>
    <h1>test</h1>
    <!-- 引入自定义的Promise.js文件 -->
    <script src="./lib/Promise.js"></script>
    <script>
      const p1 = Promise.resolve(1);
      const p2 = Promise.reject(2);
      const pAll = Promise.all([p1, p2, 999]);
      pAll
        .then(value => {
    
    
          console.log("value:", value);
        })
        .catch(reason => {
    
    
          console.log("reason:", reason);
        });
        // 以上代码的打印结果:reason: 2
    </script>
  </body>
</html>

猜你喜欢

转载自blog.csdn.net/ddx2019/article/details/114290366