使用Promise/A+ 規(guī)范,實現(xiàn)Promise

一、規(guī)范簡介

  1. 術(shù)語:

    • Promise 是具有then方法的對象或函數(shù),行為符合Promise/A+規(guī)范。
    • thenable 是定義then方法得對象或函數(shù)
    • value 是任何合法的Javascript值(包括undefined,ableable或promise)
    • 異常 exception throw 語句拋出的值
    • reason 是表明拒絕promise的原因
  2. 要求

    1. promise 的狀態(tài)

      • pending:等待狀態(tài),可以轉(zhuǎn)換成其他狀態(tài)。
      • fulfilled:成功狀態(tài),不能轉(zhuǎn)化為其他狀態(tài)。轉(zhuǎn)為該狀態(tài)需要一個value,該value不能改變。
      • rejected:失敗狀態(tài),不能轉(zhuǎn)為其他狀態(tài)。轉(zhuǎn)為改狀態(tài)需要一個reason,該reason不能改變。

      fulfilled與rejected是穩(wěn)定狀態(tài)

    2. then 方法

      • const promise2 = promise1.then(onFulfilled, onRejected)
      • then方法的參數(shù)
        • 兩個函數(shù)參數(shù)
        • onFulfilled在promise完成后被調(diào)用,onRejected在Promise被拒絕執(zhí)行后調(diào)用
        • 只能被調(diào)用一次
      • then方法的調(diào)用:可以調(diào)用多次
      • then方法的返回值:promise
        1. onFulfilled不是函數(shù),promise1的狀態(tài)是fulfilled :這時 promise2的狀態(tài)是fulfilled,值同promise1
        2. onRejected不是函數(shù),promise1的狀態(tài)是rejected:這時promise2的狀態(tài)是 rejected,拒絕原因reason同promise1
        3. onFulfilled 或者onRejected return x 返回一個返回值,進(jìn)入Promise解析過程
    3. Promise解析過程

      • 抽象模型 resolve(promise, x)
      • 如果promise和x指向相同的對象
      • 如果x是一個promise:查看x的狀態(tài) pending 則需等待狀態(tài)改變,fulfilled value 為 promise的值 ,reject reason為promise的reason
      • 如果x是一個對象或一個函數(shù): 執(zhí)行x的then方法
      • 如果x不是對象也不是函數(shù):把x作為promise的值,設(shè)置成fulfilled狀態(tài)

二、根據(jù)規(guī)范打造自己的Promise

  1. new Promise

    • 定義一個 class 來證明 promise

    • new Promise((resolve, reject) => {}),傳入一個參數(shù)(函數(shù)),該函數(shù)為立即執(zhí)行函數(shù),這里面我們起名為 executor。

    • executor 函數(shù)接收兩個參數(shù),resolve 與 reject,成功時resolve(value),失敗時reject(reason)。

    • promise 原型方法:

      • .then()
      • .catch()
      • .finally()
    • promise 靜態(tài)方法

      • Promise.resolve(value)
      • Promise.reject(reason)
      • Promise.all([p1, .....,pn])
      • Promise.allSettled([p1, .....,pn])
      • Promise.race([p1, .....,pn])

    根據(jù)以上信息,我們大致架構(gòu)如下

    class Promise {
      // 構(gòu)造器
      constructor(executor) {
        // resolve()
        let resolve = value => {}
        // reject()
        let reject = reason => {}
        // 立即執(zhí)行 executor 方法
        executor(resolve, reject);
      }
      // then 方法
      then() {}
      // catch 方法
      catch() {}
      // finall 方法
      finally() {}
    }
    
    Promise.resolve = () => {}
    Promise.reject = () => {}
    Promise.all = () => {}
    Promise.allSettled = () => {}
    Promise.race = () => {}
    
    
    
  1. promise 狀態(tài)

    規(guī)范要求:Promise 狀態(tài)

    • Promise 存在三個狀態(tài)(state):pending,fulfilled,rejected
    • pending 為初始狀態(tài),可轉(zhuǎn)化為 fulfilled 和 rejected
    • 成功后,不可轉(zhuǎn)為其他狀態(tài),且需要一個不可變值(value)
    • 失敗后,不可轉(zhuǎn)為其他狀態(tài),且需要一個不可變原因(reason)

    new Promise((resolve, reject) => {})

    • 成功時 resolve(value),接受參數(shù)value,狀態(tài)改為 fulfilled,此為穩(wěn)定狀態(tài),不可再次改變。
    • 失敗時 reject(reason),接受參數(shù) reason,狀態(tài)改為 rejected,此為穩(wěn)定狀態(tài),不可再次改變。
    • 執(zhí)行 executor 時報錯,則直接執(zhí)行 reject(reason)

根據(jù)以上信息,我們得到以下代碼:

class Promise {
  // 構(gòu)造器
  constructor(executor) {
    // 狀態(tài) 默認(rèn)為 pending 狀態(tài)
    this.state = "pending";
    // 成功的值
    this.value = undefined;
    // 失敗的原因
    this.reason = undefined;
    // resolve(value) 將狀態(tài)改為 fulfilled 狀態(tài)
    let resolve = value => {
      this.value = value;
      this.state = "fulfilled";
    }
    // reject(reason) 將狀態(tài)改為 rejected 狀態(tài)
    let reject = reason => {
      this.reason = reason;
      this.state = "rejected";
    }
    // 如果 executor 報錯 立即執(zhí)行 reject
    try{
      // 立即執(zhí)行 executor 方法
      executor(resolve, reject);
    } catch(error) {
      reject(error);
    }
  }
  // then 方法
  then() {}
  // catch 方法
  catch() {}
  // finall 方法
  finally() {}
}

Promise.resolve = () => {}
Promise.reject = () => {}
Promise.all = () => {}
Promise.allSettled = () => {}
Promise.race = () => {}

  1. .then()方法

    規(guī)范要求:.then()

    由于.then()要求很多,我們進(jìn)行拆解,分為:

    • 基本要求
    • 鏈?zhǔn)秸{(diào)用。

    1. 基本要求:

    • 一個 Promise 必須提供 then 方法,訪問其當(dāng)前或最終value或reason

    • then 接受兩個參數(shù) promise.then(onFulfilled, onRejected)

      • then的兩個參數(shù)為可選參數(shù)。
      • 如果參數(shù)不是函數(shù),則必須將其忽略。
      • 如果 onFulfilled 是函數(shù)
        • 必須在promise 成功后調(diào)用,以promise的值(value)作為第一個參數(shù),不能調(diào)用多次。
      • 如果 onRejected 是函數(shù)
        • 必須在promise 失敗后調(diào)用,以promise的原因(reason)作為第一個參數(shù),不能調(diào)用多次。
      • onFulfilled 及 onRejected 必須作為函數(shù)調(diào)用(沒有this值)
    • 異步調(diào)用:onFulfilled 或 onRejected 在執(zhí)行上下文堆棧(緊包含平臺代碼)之前不能調(diào)用

    class Promise {
      // 構(gòu)造器
      constructor(executor) {...}
      // then 方法
      then(onFulfilled, onRejected) {
        // onFulfilled 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接返回 value
        onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value;
        // onRejected 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接拋出錯誤
        onRejected = isFunction(onRejected) ? onRejected : error => { throw error};
        // 如果 Promise 為 成功狀態(tài) 調(diào)用 onFulfilled 方法 傳入成功的 value
        if(this.state === "fulfilled") {
          // 異步調(diào)用
          setTimeout(() => {
            onFulfilled(this.value);
          }, 0);
        }
        // 如果 Promise 為 失敗狀態(tài) 調(diào)用 onRejected 方法 傳入失敗的 reason
        if (this.state === "rejected") {
          // 異步調(diào)用
          setTimeout(() => {
            onRejected(this.reason);
          }, 0);
        }
      }
      // catch 方法
      catch() {}
      // finall 方法
      finally() {}
    }
    
    Promise.resolve = () => {}
    Promise.reject = () => {}
    Promise.all = () => {}
    Promise.allSettled = () => {}
    Promise.race = () => {}
    
    // 輔助方法
    // 判斷 obj 是不是 Function
    function isFunction(obj) {
      return !!obj && typeof obj === "function";
    }
    // 判斷 obj 是不是 Object
    function isObject(obj) {
      return !!obj && typeof obj === "object";
    }
    // 判斷 obj 是不是 Promise
    function isPromise(obj) {
      return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
    }
    

    特殊情況:

    new Promise((resolve, reject) => {
      setTimeout(() => {
         resolve(1);
         // reject("錯誤");
      }, 200)
    })
    

    當(dāng) resolve 或者reject 在 setTimeout內(nèi)執(zhí)行時,由于setTimeout為異步方法,會先把它放到宏任務(wù)隊列當(dāng)中等待當(dāng)前任務(wù)執(zhí)行完成之后在執(zhí)行。當(dāng)前任務(wù)執(zhí)行到.then 時 Promise的狀態(tài)(state)還是pending(等待狀態(tài)),這時就會出現(xiàn)問題。

    解決方案:

    規(guī)范要求中有一條要求:

    • then 可能在同一 Promise中多次被調(diào)用

      let p = new Promise();
      p.then();
      p.then();
      
      • 當(dāng)promise 成功,則所有相應(yīng)的 onFulfilled回調(diào)必須按照其原始調(diào)用的執(zhí)行順序執(zhí)行then
      • 當(dāng)promise失敗,則所有相應(yīng)的onRejected回調(diào)必須按照其原始調(diào)用的執(zhí)行順序進(jìn)行then

    根據(jù)這一要求,我們可以在then中增加 state為pending的處理,將onFulfilled 與onRejected方法存到各自的數(shù)組里面,一旦setTimeout中的resolve或者reject執(zhí)行了 ,就調(diào)用它們。

    這樣除了能解決setTimeout異步問題,也能解決統(tǒng)一Promise多次調(diào)用then問題。

    根據(jù)以上信息,得到以下代碼:

    class Promise {
      constructor(executor) {
        this.state = "pending";
        this.value = undefined;
        this.reason = undefined;
        // 成功存放方法的數(shù)組
        this.onResolvedCallbacks = [];
        // 失敗存放方法的數(shù)組
        this.onRejectedCallbacks = [];
        let resolve = value => {
          this.value = value;
          this.state = "fulfilled";
          // 一旦 resolve 執(zhí)行, 則按順序 調(diào)用 成功數(shù)組 中的函數(shù)
          this.onResolvedCallbacks.forEach(fn => {
            fn();
          });
        }
        let reject = reason => {
          this.reason = reason;
          this.state = "rejected";
          // 一旦 reject 執(zhí)行, 則按順序 調(diào)用 失敗數(shù)組 中的函數(shù)
          this.onRejectedCallbacks.forEach(fn => {
            fn();
          });
        }
        try{
          executor(resolve, reject);
        } catch(error) {
          reject(error);
        }
      }
      // then 方法
      then(onFulfilled, onRejected) {
        onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value;
        onRejected = isFunction(onRejected) ? onRejected : error => { throw error};
        if(this.state === "fulfilled") {
          setTimeout(() => {
            onFulfilled(this.value);
          }, 0);
        }
        if (this.state === "rejected") {
          setTimeout(() => {
            onRejected(this.reason);
          }, 0);
        }
        // 如果 Promise 為 等待狀態(tài) 
        // 由于不知道 是成功還是失敗,則需要兩個數(shù)組,
        // 將成功或失敗各自對應(yīng)的方法 push 到各自的數(shù)組當(dāng)中
        if (this.state === "pending") {
          // onFulfilled 傳入到成功數(shù)組
          this.onResolvedCallbacks.push(() => {
            // 異步調(diào)用
            setTimeout(() => {
              onFulfilled(this.value);
            }, 0);
          });
          // onRejected 傳入到成功的數(shù)組
          this.onRejectedCallbacks.push(() => {
            // 異步調(diào)用
            setTimeout(() => {
              onRejected(this.reason);
            }, 0);
          })
        }
      }
      catch() {}
      finally() {}
    }
    
    Promise.resolve = () => {}
    Promise.reject = () => {}
    Promise.all = () => {}
    Promise.allSettled = () => {}
    Promise.race = () => {}
    
    function isFunction(obj) {
      return !!obj && typeof obj === "function";
    }
    function isObject(obj) {
      return !!obj && typeof obj === "object";
    }
    function isPromise(obj) {
      return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
    }
    

    2. 鏈?zhǔn)秸{(diào)用

    日常使用 Promise 時,常用到 new promise().then().then(),這就是鏈?zhǔn)秸{(diào)用。通過鏈?zhǔn)秸{(diào)用,我們就可以解決回調(diào)地獄問題。

    規(guī)范中規(guī)定:

    1. then 必須返回一個promise

      promise2 = promise1.then(onFulfilled, onRejected);

      • 如果 onFulfilled 或 onRejected 執(zhí)行時報錯,則直接返回失敗
      • onFulfilled 不是函數(shù),promise1的狀態(tài)是fulfilled :這時 promise2的狀態(tài)是fulfilled,值同promise1
      • onRejected 不是函數(shù),promise1 的狀態(tài)是 rejected:這時promise2的狀態(tài)是 rejected,拒絕原因 reason 同promise1
      • 如果一個 onFulfilled 或 onRejected 返回一個值 x(自己return x),則需要對x進(jìn)行處理,處理的函數(shù)叫做:resolvePromise(promise2, x)
    2. 規(guī)范中的resolvePromise(promise2, x) 規(guī)定

      • 如果promise和x指向相同的對象,會導(dǎo)致循環(huán)調(diào)用,直接返回失敗
      • 如果x是一個promise:查看x的狀態(tài) pending 則需等待狀態(tài)改變,fulfilled value 為 promise的值 ,reject reason為promise的reason
      • 如果x是一個對象或一個函數(shù): 執(zhí)行x的then方法
        • 如果 沒有x.then 則直接返回失敗
        • 如果 有x.then 且為函數(shù),則執(zhí)行 then.call(),參數(shù):x 作為this,成功時的回調(diào),失敗時的回調(diào)。
          • 如果成功的回調(diào)還是promise,值為y,再次調(diào)用 resolvePromise(promise2, y, resolve, reject)
          • 如果失敗,則執(zhí)行失敗回到,原因為r,直接返回失敗
          • 成功和失敗只能調(diào)用一個,所以設(shè)定一個isCalled來防止多次調(diào)用
        • 如果 有x.then但不是函數(shù),則將x作為promise的值
      • 如果x不是對象也不是函數(shù):把x作為promise的值,設(shè)置成fulfilled狀態(tài)
      class Promise {
        // 構(gòu)造器
        constructor(executor) {...}
        // then 方法
        then(onFulfilled, onRejected) {
          // onFulfilled 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接返回 value
          onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value;
          // onRejected 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接拋出錯誤
          onRejected = isFunction(onRejected) ? onRejected : error => { throw error};
          // 如果 Promise 為 成功狀態(tài) 調(diào)用 onFulfilled 方法 傳入成功的 value
          if(this.state === "fulfilled") {
            // 異步調(diào)用
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            }, 0);
          }
          // 如果 Promise 為 失敗狀態(tài) 調(diào)用 onRejected 方法 傳入失敗的 reason
          if (this.state === "rejected") {
            // 異步調(diào)用
            setTimeout(() => {
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            }, 0);
          }
          // 如果 Promise 為 等待狀態(tài) 
          // 由于不知道 是成功還是失敗,則需要兩個數(shù)組,
          // 將成功或失敗各自對應(yīng)的方法 push 到各自的數(shù)組當(dāng)中
          if (this.state === "pending") {
            // onFulfilled 傳入到成功數(shù)組
            this.onResolvedCallbacks.push(() => {
              // 異步調(diào)用
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (error) {
                  reject(error);
                }
              }, 0);
            });
            // onRejected 傳入到成功的數(shù)組
            this.onRejectedCallbacks.push(() => {
              // 異步調(diào)用
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (error) {
                  reject(error);
                }
              }, 0);
            });
          }
        }
        // catch 方法
        catch() {}
        // finall 方法
        finally() {}
      }
      
      Promise.resolve = () => {}
      Promise.reject = () => {}
      Promise.all = () => {}
      Promise.allSettled = () => {}
      Promise.race = () => {}
      
      function resolvePromise(promise2, x, resolve, reject) {
        // 如果 x 和 promise2 指向相同
        if (x === promise2) {
          reject(new TypeError("Chaining cycle detected for promise"));
        }
        // 如果x為promise 則采用其狀態(tài)
        if (isPromise(x)) {
          if (x.state === "pending") {
            return x.then(()=> {
              resolve(x.value);
            }, () => {
              reject(x.reason);
            })
          }
          if (x.state === "fulfilled") {
            return resolve(x.value);
          }
          if (x.state === "rejected") {
            return reject(x.reason);
          }
        } else if (isObject(x) || isFunction(x)) {
          // 如果x是對象或者函數(shù)
          let then;
          // 取 x.then
          try {
            then = x.then;
          } catch (error) { // 取x.then 如果報錯則直接失敗
            reject(error);
          }
          // 如果 then 是 函數(shù)
          if (isFunction(then)) {
            // 只可以調(diào)用一個
            let isCalled = false;
            try {
              then.call(x, y => {
                if (isCalled) {
                  return;
                }
                isCalled = true;
                resolvePromise(promise2, y, resolve, reject);
              }, r => {
                if (isCalled) {
                  return;
                }
                isCalled = true;
                reject(r);
              })
            } catch (error) { // 執(zhí)行then報錯則直接返回失敗
              if (isCalled) {
                return;
              }
              isCalled = true;
              reject(error);
            }
          } else { // 如果不是方法 則把x作為promsie的值
            resolve(x);
          }
        } else { // x 既不是方法也不是函數(shù)  則把x作為promsie的值
          resolve(x);
        }
      }
      // 輔助方法
      // 判斷 obj 是不是 Function
      function isFunction(obj) {
        return !!obj && typeof obj === "function";
      }
      // 判斷 obj 是不是 Object
      function isObject(obj) {
        return !!obj && typeof obj === "object";
      }
      // 判斷 obj 是不是 Promise
      function isPromise(obj) {
        return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
      }
      
  1. catch 實現(xiàn)

    報錯就走這個方法

      // catch 方法
      catch(fn) {
        return this.then(null, fn);
      }
    
  1. finall 實現(xiàn)

    不管成功還是失敗,最后都要執(zhí)行該方法,與 then不同

    參數(shù):onFinally :Promise結(jié)束后調(diào)用的function

    返回值: 返回了一個設(shè)置了finally回調(diào)函數(shù)的Promise對象

    描述:如果你想在 promise 執(zhí)行完畢后無論其結(jié)果怎樣都做一些處理或清理時,finally() 方法可能是有用的。

    finally() 雖然與 .then(onFinally, onFinally) 類似,它們不同的是:

    • 調(diào)用內(nèi)聯(lián)函數(shù)時,不需要多次聲明該函數(shù)或為該函數(shù)創(chuàng)建一個變量保存它。
    • 由于無法知道promise的最終狀態(tài),所以finally的回調(diào)函數(shù)中不接收任何參數(shù),它僅用于無論最終結(jié)果如何都要執(zhí)行的情況。
    • Promise.resolve(2).then(() => {}, () => {}) (resolved的結(jié)果為undefined)不同,Promise.resolve(2).finally(() => {}) resolved的結(jié)果為 2
    • 同樣,Promise.reject(3).then(() => {}, () => {}) (resolved 的結(jié)果為undefined), Promise.reject(3).finally(() => {}) rejected 的結(jié)果為 3。

    注意:finally回調(diào)中 throw(或返回被拒絕的promise)將以 throw() 指定的原因拒絕新的promise.

      // finall 方法
      finally(fn) {
        return new Promise((resolve, reject) => {
          try {
            fn();
          } catch (error) {
            reject(error);
          }
          if (this.state === "fulfilled") {
            resolve(this.value);
          }
          if (this.state === "rejected") {
            reject(this.reason);
          }
        })
      }
    
  1. Promise.resolve 實現(xiàn)

    Promise.resolve = (value) => {
      return new Promise((resolve, reject) => {
        resolve(value);
      });
    }
    
  1. Promise.reject 實現(xiàn)

    Promise.reject = (reason) => {
      return new Promise((resolve, reject) => {
        resolve(reason);
      });
    }
    
  1. Promise.all 實現(xiàn)

    all 方法

    • Promise.all([p1, p2, p3])用于將多個promise實例,包裝成一個新的Promise實例,返回的實例就是普通的promise

    • 它接收一個數(shù)組作為參數(shù)

    • 數(shù)組里可以是Promise對象,也可以是別的值,只有Promise會等待狀態(tài)改變

    • 當(dāng)所有的子Promise都完成,該Promise完成,返回值是全部值得數(shù)組

    • 有任何一個失敗,該Promise失敗,返回值是第一個失敗的子Promise結(jié)果

    Promise.all = (promiseArr) => {
      let result = [];
      let i = 0;
      function handleData(index, value, resolve) {
        result[index] = value;
        i++;
        if (i == promiseArr.length) {
          resolve(result);
        }
      }
      return new Promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          if (isPromise(promiseArr[i])) {
            promiseArr[i].then(value => {
              handleData(i, value, resolve);
            }, reject)
          } else {
            handleData(i, promiseArr[i], resolve);
          }
        }
      })
    }
    
  1. Promise.allSettled 實現(xiàn)

    allSettled 方法

    • Promise.allSettled([p1, p2, p3])用于將多個promise實例,包裝成一個新的Promise實例,返回的實例就是普通的promise

    • 它接收一個數(shù)組作為參數(shù)

    • 數(shù)組里是Promise對象

    • 當(dāng)所有的子Promise都完成,該Promise完成,返回值是一個對象 包含每個子promise執(zhí)行后得狀態(tài)及對應(yīng)得值或原因

    • 只要所有得子promise都執(zhí)行完成,結(jié)果Promise為fulfilled狀態(tài)

    Promise.allSettled = (promiseArr) => {
      let result = [];
      let i = 0;
      function handleData(index, data, resolve) {
        result[index] = data;
        i++;
        if (i == promiseArr.length) {
          resolve(result);
        }
      }
      return new promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          promiseArr[i].then(value => {
            handleData(i, {state: "fulfilled", value: value}, resolve);
          }, error => {
            handleData(i, {state: "rejected", reason: error}, resolve);
          });
        }
      });
    }
    
  1. Promise.race 實現(xiàn)

    race 方法 有一個完成就算完成,返回的promise狀態(tài)同第一個完成的

    Promise.race = (promiseArr) => {
      return new promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          promiseArr[i].then(resolve, reject);
        }
      });
    }
    
  1. 完整代碼

    class Promise {
      // 構(gòu)造器
      constructor(executor) {
        // 狀態(tài) 默認(rèn)為 pending 狀態(tài)
        this.state = "pending";
        // 成功的值
        this.value = undefined;
        // 失敗的原因
        this.reason = undefined;
        // 成功存放方法的數(shù)組
        this.onResolvedCallbacks = [];
        // 失敗存放方法的數(shù)組
        this.onRejectedCallbacks = [];
        // resolve(value) 將狀態(tài)改為 fulfilled 狀態(tài)
        let resolve = value => {
          this.value = value;
          this.state = "fulfilled";
          // 一旦 resolve 執(zhí)行, 則按順序 調(diào)用 成功數(shù)組 中的函數(shù)
          this.onResolvedCallbacks.forEach(fn => {
            fn();
          });
        }
        // reject(reason) 將狀態(tài)改為 rejected 狀態(tài)
        let reject = reason => {
          this.reason = reason;
          this.state = "rejected";
          // 一旦 reject 執(zhí)行, 則按順序 調(diào)用 失敗數(shù)組 中的函數(shù)
          this.onRejectedCallbacks.forEach(fn => {
            fn();
          });
        }
        // 如果 executor 報錯 立即執(zhí)行 reject
        try{
          // 立即執(zhí)行 executor 方法
          executor(resolve, reject);
        } catch(error) {
          reject(error);
        }
      }
      // then 方法
      then(onFulfilled, onRejected) {
        // onFulfilled 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接返回 value
        onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value;
        // onRejected 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接拋出錯誤
        onRejected = isFunction(onRejected) ? onRejected : error => { throw error};
        // 如果 Promise 為 成功狀態(tài) 調(diào)用 onFulfilled 方法 傳入成功的 value
        if(this.state === "fulfilled") {
          // 異步調(diào)用
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        }
        // 如果 Promise 為 失敗狀態(tài) 調(diào)用 onRejected 方法 傳入失敗的 reason
        if (this.state === "rejected") {
          // 異步調(diào)用
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        }
        // 如果 Promise 為 等待狀態(tài) 
        // 由于不知道 是成功還是失敗,則需要兩個數(shù)組,
        // 將成功或失敗各自對應(yīng)的方法 push 到各自的數(shù)組當(dāng)中
        if (this.state === "pending") {
          // onFulfilled 傳入到成功數(shù)組
          this.onResolvedCallbacks.push(() => {
            // 異步調(diào)用
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            }, 0);
          });
          // onRejected 傳入到成功的數(shù)組
          this.onRejectedCallbacks.push(() => {
            // 異步調(diào)用
            setTimeout(() => {
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            }, 0);
          });
        }
      }
      // catch 方法
      catch(fn) {
        return this.then(null, fn);
      }
      // finall 方法
      finally(fn) {
        return new Promise((resolve, reject) => {
          try {
            fn();
          } catch (error) {
            reject(error);
          }
          if (this.state === "fulfilled") {
            resolve(this.value);
          }
          if (this.state === "rejected") {
            reject(this.reason);
          }
        })
      }
    }
    
    Promise.resolve = (value) => {
      return new Promise((resolve, reject) => {
        resolve(value);
      });
    }
    Promise.reject = (reason) => {
      return new Promise((resolve, reject) => {
        resolve(reason);
      });
    }
    Promise.all = (promiseArr) => {
      let result = [];
      let i = 0;
      function handleData(index, value, resolve) {
        result[index] = value;
        i++;
        if (i == promiseArr.length) {
          resolve(result);
        }
      }
      return new Promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          if (isPromise(promiseArr[i])) {
            promiseArr[i].then(value => {
              handleData(i, value, resolve);
            }, reject)
          } else {
            handleData(i, promiseArr[i], resolve);
          }
        }
      })
    }
    Promise.allSettled = (promiseArr) => {
      let result = [];
      let i = 0;
      function handleData(index, data, resolve) {
        result[index] = data;
        i++;
        if (i == promiseArr.length) {
          resolve(result);
        }
      }
      return new promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          promiseArr[i].then(value => {
            handleData(i, {state: "fulfilled", value: value}, resolve);
          }, error => {
            handleData(i, {state: "rejected", reason: error}, resolve);
          });
        }
      });
    }
    Promise.race = (promiseArr) => {
      return new promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          promiseArr[i].then(resolve, reject);
        }
      });
    }
    
    function resolvePromise(promise2, x, resolve, reject) {
      // 如果 x 和 promise2 指向相同
      if (x === promise2) {
        reject(new TypeError("Chaining cycle detected for promise"));
      }
      // 如果x為promise 則采用其狀態(tài)
      if (isPromise(x)) {
        if (x.state === "pending") {
          return x.then(()=> {
            resolve(x.value);
          }, () => {
            reject(x.reason);
          })
        }
        if (x.state === "fulfilled") {
          return resolve(x.value);
        }
        if (x.state === "rejected") {
          return reject(x.reason);
        }
      } else if (isObject(x) || isFunction(x)) {
        // 如果x是對象或者函數(shù)
        let then;
        // 取 x.then
        try {
          then = x.then;
        } catch (error) { // 取x.then 如果報錯則直接失敗
          reject(error);
        }
        // 如果 then 是 函數(shù)
        if (isFunction(then)) {
          // 只可以調(diào)用一個
          let isCalled = false;
          try {
            then.call(x, y => {
              if (isCalled) {
                return;
              }
              isCalled = true;
              resolvePromise(promise2, y, resolve, reject);
            }, r => {
              if (isCalled) {
                return;
              }
              isCalled = true;
              reject(r);
            })
          } catch (error) { // 執(zhí)行then報錯則直接返回失敗
            if (isCalled) {
              return;
            }
            isCalled = true;
            reject(error);
          }
        } else { // 如果不是方法 則把x作為promsie的值
          resolve(x);
        }
      } else { // x 既不是方法也不是函數(shù)  則把x作為promsie的值
        resolve(x);
      }
    }
    // 輔助方法
    // 判斷 obj 是不是 Function
    function isFunction(obj) {
      return !!obj && typeof obj === "function";
    }
    // 判斷 obj 是不是 Object
    function isObject(obj) {
      return !!obj && typeof obj === "object";
    }
    // 判斷 obj 是不是 Promise
    function isPromise(obj) {
      return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
    }
    
  1. 驗證promise是否正確

    • 先在后面加上下述代碼

    • npm 有一個promises-aplus-tests插件 npm i promises-aplus-tests -g 可以全局安裝 mac用戶最前面加上sudo

    • 命令行 promises-aplus-tests [js文件名] 即可驗證

    // 目前是通過他測試 他會測試一個對象
    // 語法糖
    Promise.defer = Promise.deferred = function () {
      let dfd = {}
      dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
      });
      return dfd;
    }
    module.exports = Promise;
    //npm install promises-aplus-tests 用來測試自己的promise 符不符合promisesA+規(guī)范
    
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容