2021-11-29 手寫PromiseA+

包含promise原型對象的方法:.then() 和 .catch();
promise對象上的方法: resolve() / reject() / all() / race() ;
自定義promise對象方法:
Promise.resolvedDelay(value, time) 規定時間成功
Promise.rejectedDalay(reason, time ) 規定時間失敗

/*
  自定義Promise函數模塊: IIFE
*/

(function (window) {

  const PENDING = 'pending';
  const RESOLVED = 'resolved';
  const REJECTED = 'rejected';

  /**
    * Promise構造函數
    * excutor: 執行器函數(同步執行)
   */
  function Promise(excutor) {

    // 將當前promise對象保存起來
    const that = this;
    that.status = PENDING; // 給promise對象指定status屬性,初始值為PENDING
    that.data = undefined; // 給promise對象指定一個用于存出結果數據的屬性
    that.callbacks = []; // 每個元素的結構: { onResolved() {},  onRejected() {} }

    function resolve(value) {
      // 如果當前狀態不是PENDING,直接結束
      if (that.status !== PENDING) return;

      // 將狀態改為RESOLVED
      that.status = RESOLVED;
      // 保存value數據
      that.data = value;
      // 如果有待執行callback函數,立即異步執行回調函數 onResolved
      if (that.callbacks.length > 0) {
        // 放入隊列中執行所有成功的回調
        setTimeout(() => {
          that.callbacks.forEach(callbacksObj => {
            callbacksObj.onResolved(value);
          });
        });
      };

    };

    function reject(reason) {
      // 如果當前狀態不是PENDING,直接結束
      if (that.status !== PENDING) return;

      // 將狀態改為REJECTED
      that.status = REJECTED;
      // 保存value數據
      that.data = reason;
      // 如果有待執行的callback函數,立即異步執行回調函數onREJECTED
      if (that.callbacks.length > 0) {
        setTimeout(() => {
          that.callbacks.forEach((callbacksObj) => {
            callbacksObj.onRejected(reason);
          });
        });
      };
    };

    // 立即同步執行excutor 
    try {
      excutor(resolve, reject);
    } catch (error) {  // 如果執行器拋出異常,promise對象變為REJECTED狀態
      reject(error);
    }
  };
  /* 
    Promise原型對象的then()
    指定成功和失敗的回調函數
    返回一個新的promise對象
  */
  Promise.prototype.then = function (onResolved, onRejected) {
    // 指定兩個回調函數的默認值(必須是函數)
    onResolved = typeof onResolved === 'function' ? onResolved : value => value;  // 向后傳遞成功的value
    // 指定默認的失敗的回調(實現錯誤 / 異常穿透的關鍵點)
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };  // 向后傳遞失敗的reason


    const that = this;
    // 返回一個新的promise對象
    return new Promise((resolve, reject) => {

      /* 
        調用指定回調函數處理, 根據執行結果,改變return的promise的狀態。
      */
      function handle(callback) {
        /*
          1. 如果拋出異常,return的promise就會失敗,reason 就是 error
          2. 如果回調函數返回的不是promise, return的promise就會是成功, value就是返回的值
          3. 如果回調函數返回的是promise, return的promise結果就是這個promise 的結果
        */
        try {
          const result = callback(that.data);
          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          reject(error);
        };
      }

      // 當前狀態還是pending狀態,將回調函數保存起來
      if (that.status === PENDING) {
        that.callbacks.push({
          onResolved() {
            handle(onResolved);
          },
          onRejected() {
            handle(onRejected);
          },
        });
      } else if (that.status === RESOLVED) {  // 如果當前是resolved狀態,異步執行onResolved并改變return的promise狀態
        setTimeout(() => {
          handle(onResolved);
        });
      } else {  //  如果當前是resolved狀態,異步執行onRejected并改變return的promise狀態。
        setTimeout(() => {
          handle(onRejected);
        });
      }
    })
  };
  /* 
    Promise原型對象的catch()
    指定失敗的回調函數
    返回一個新的promise對象
  */
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
  };

  /* 
    Promise函數對象的resolve方法
    返回一個指定結果的成功的promise
  */
  Promise.resolve = function (value) {
    // 返回一個成功的promise
    return new Promise((resolve, reject) => {

      if (value instanceof Promise) {
        // 是promise的話,使用value的結果作為promise的結果
        value.then(resolve, reject);
      } else {
        // promise變為成功,數據是value
        resolve(value);
      };
    });
  };

  /* 
    Promise函數的reject方法
    返回一個指定結果的失敗的promise
  */
  Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  };

  /* 
    Promise函數的all方法
    返回一個promise, 只有當所有promise都成功時才成功,否則只要有一個失敗的就失敗
  */
  Promise.all = function (promiseArr) {
    const valuesArr = new Array(promiseArr.length); // 保存所有成功的value值
    let resolvedCount = 0;  // 用來保存成功的promise數量
    return new Promise((resolve, reject) => {
      // 遍歷promise獲取每個Promise的結果
      promiseArr.forEach((pObj, index) => {
        Promise.resolve(pObj).then(
          value => {
            // 當前的p成功,將成功的value放入數組中
            valuesArr[index] = value; // 注意順序問題,按照promiseArr的順序放入
            resolvedCount++;
            // 如果全部成功了,將return的promise改變成功
            if (resolvedCount === promiseArr.length) {
              resolve(valuesArr);
            };
          },
          reason => {  // 只要有一個失敗了,return的promise就失敗了
            reject(reason);
          }
        )
      })
    })
  };

  /* 
    Promise函數的race方法
    返回一個promise,其結果由第一個完成的promise決定,第一個失敗就是失敗,否則就是成功
  */
  Promise.race = function (promiseArr) {
    return new Promise((resolve, reject) => {
      // 遍歷每個promise獲取結果
      promiseArr.forEach((pObj, index) => {
        if (pObj instanceof Promise) {  // 可以判斷pObj是不是promise,也可以 Promie.resolve(pObj).then()
          pObj.then(
            value => {  // 一旦有成功的,將return 變為成功
              resolve(value);
            },
            reason => {
              reject(reason);
            },
          );
        } else {
          resolve(pObj);
        };
      });
    });
  };


  /* 
    Promise函數對象上的 resolveDelay方法
    返回一個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函數對象上的 rejectDelay方法
    返回一個promise對象,它在指定的時間后才失敗
  */
  Promise.rejectDelay = function (reason, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason);
      }, time);
    });
  };

  // 向外暴露Promise函數
  window.Promise = Promise;
})(window);

測試代碼:

    const p4 = new Promise((resolve) => {
      setTimeout(() => {
        resolve(4);
      }, 1000);
    });
    const p1 = Promise.resolve(1);
    const p3 = Promise.resolve(Promise.reject(3));
    const p5 = Promise.resolve(5);
    const p2 = Promise.reject(Promise.resolve(2));

    p4.then((value) => {
      console.log("p4", value);
    });
    p1.then((value) => console.log("p1", value));
    p2.catch((value) => console.log("p2", value));
    p3.catch((reason) => console.log("p3", reason));

    const pAll = Promise.all([p4, 2, p1, p5]);
    pAll.then(
      (values) => {
        console.log("pAll onResolved()", values);
      },
      (reason) => {
        console.log("pAll onRejected()", reason);
      }
    );
    const pRace = Promise.race([p1, p3, p2, p5, p4]);
    pRace.then(
      (value) => {
        console.log("pRace onResolved()", value);
      },
      (reason) => {
        console.log("pRace onRejected()", reason);
      }
    );

    const p6 = Promise.resolveDelay(66, 2000);
    const p7 = Promise.rejectDelay(77, 3000);
    p6.then((value) => console.log("p6", value));
    p7.catch((reason) => console.log("p7", reason));

撒花??ヽ(°▽°)ノ?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容