手寫(xiě)Promise——基于es6的Promise實(shí)現(xiàn)(含詳細(xì)注釋?zhuān)?/h1>

1. Promise A+ 規(guī)范

2. 代碼實(shí)現(xiàn)

github地址:https://github.com/whu-luojian/Promise.git


// promise的狀態(tài)枚舉

const STATUS = {

  PENDING: 0,

  FULFILLED: 1,

  REJECTED: 2

}

class Promise {

  constructor(task) {    

    // promise初始狀態(tài)

    this.status = STATUS.PENDING;

    // resolve時(shí)返回的數(shù)據(jù)

    this.resolveData = null;

    // reject時(shí)返回的數(shù)據(jù)

    this.rejectData = null;

    // resolve和reject時(shí)執(zhí)行的回調(diào)隊(duì)列

    // promise的resolve和reject為異步響應(yīng)時(shí)车荔,即調(diào)用then時(shí)promise為

    // pending狀態(tài),則將傳入then的函數(shù)加入該隊(duì)列,等待promise resolve或

    // reject時(shí)執(zhí)行該隊(duì)列

    this.onFulfilledList = [];

    this.onRejectedList = [];

    /**

    * promise成功平项,執(zhí)行onFulfilledList回調(diào)

    * @param {*} data 

    */

    this.onResolve = (data) => {

      if(this.status === STATUS.PENDING) {

        this.status = STATUS.FULFILLED;

        this.resolveData = data;

        this.onFulfilledList.forEach(fn => {

          fn(this.resolveData)

        })

      }

    }

    /**

    * promise失敗倾剿,執(zhí)行onRejectedList回調(diào)

    * @param {*} err 

    */

    this.onReject = (err) => {

      if(this.status === STATUS.PENDING) {

        this.status = STATUS.REJECTED;

        this.rejectData = err;

        this.onRejectedList.forEach(fn => {

          fn(this.rejectData)

        })

      }

    }

    /**

    * promise解析, 根據(jù)then 返回?cái)?shù)據(jù)類(lèi)型不同封裝不同的promise

    * 返回栗菜,以便實(shí)現(xiàn)then的鏈?zhǔn)秸{(diào)用及Promise的thenable特性 

    * @param {*當(dāng)前then return數(shù)據(jù)} data 

    * @param {*當(dāng)前then的resolve} resolve 

    * @param {*當(dāng)前then的reject} reject 

    */

    this.resolvePromise = (data, resolve, reject) => {

      // then return 的數(shù)據(jù)是一個(gè)promise

      if(data instanceof Promise) {

        if(data.status === STATUS.PENDING) {

          data.then((val) => {

            this.resolvePromise(val, resolve, reject);

          }, reject)

        } else if (data.status === STATUS.FULFILLED) {

          resolve(data.resolveData)

        } else {

          reject(data.rejectData)

        }

      } 

      // then return的是一個(gè)對(duì)象,若對(duì)象具有then方法骡男,則可使用此方法作為新的then

      // Promise的thenable特性基于此

      else if(data !== null && data instanceof Object) {

        try {

          let then = data.then

          if(then instanceof Function) {

            then.call(data, (val) => {

              this.resolvePromise(val, resolve, reject);

            }, reject)

          } else {

            resolve(data)

          }

        } catch (err) {

          reject(err)

        }

      }

      // then return 的是基本數(shù)據(jù)或undefined

      else {

        resolve(data)

      }

    }

    // 執(zhí)行傳入的任務(wù)task

    try {

      task(this.onResolve.bind(this), this.onReject.bind(this))

    } catch (err) {

      this.onReject(err)

    }

  }

  /**

  * then回調(diào)赃蛛,返回一個(gè)promise

  * 說(shuō)明:傳入then的參數(shù)不是函數(shù)的話(huà)庇茫,直接忽略港粱,及在返回的新promise中直接resolve或reject目前

  * promise的數(shù)據(jù),傳入then的參數(shù)是函數(shù)的話(huà)旦签,則直接已目前promise的數(shù)據(jù)為參數(shù)執(zhí)行該函數(shù)查坪,并

  * 根據(jù)函數(shù)返回值情況確定新promise的狀態(tài)

  * @param {*成功} onFulfilled 

  * @param {*失敗} onRejected 

  */

  then(onFulfilled, onRejected) {

    let promise;

    // pending狀態(tài)下將傳入then的函數(shù)加入promise對(duì)應(yīng)的回調(diào)隊(duì)列

    // 等待promise狀態(tài)改變后執(zhí)行

    if(this.status === STATUS.PENDING) {

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

        this.onFulfilledList.push(() => {

          // 傳入then的參數(shù)不是函數(shù)則忽略

          if(!(onFulfilled instanceof Function)) {

            resolve(this.resolveData)

          } else {

            let data = onFulfilled(this.resolveData)

            this.resolvePromise(data, resolve, reject)

          }

        })

        this.onRejectedList.push(() => {

          // 傳入then的參數(shù)不是函數(shù)則忽略

          if(!(onRejected instanceof Function)) {

            reject(this.rejectData)

          } else {

            let data = onRejected(this.rejectData)

            this.resolvePromise(data, resolve, reject)

          } 

        })

      })

    }

    // fulfilled狀態(tài)下以promise的resolveData為參數(shù)執(zhí)行傳入then的

    // 成功回調(diào)函數(shù),再根據(jù)此函數(shù)的返回值封裝新的promise返回

    else if (this.status === STATUS.FULFILLED) {

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

        // 傳入then的參數(shù)不是函數(shù)則忽略宁炫,直接resolve

        if(!(onFulfilled instanceof Function)) {

          resolve(this.resolveData)

        } else {

          let data = onFulfilled(this.resolveData)

          this.resolvePromise(data, resolve, reject)

        }      

      })

    }

    // rejected狀態(tài)類(lèi)似fulfilled狀態(tài)

    else {

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

        // 傳入then的參數(shù)不是函數(shù)則忽略偿曙,直接reject

        if(!(onRejected instanceof Function)) {

          reject(this.rejectData)

        } else {

          let data = onRejected(this.rejectData)

          this.resolvePromise(data, resolve, reject)

        }        

      })

    }

    return promise

  }

  /**

  * catch方法

  * @param {*reject函數(shù)} rejectFn 

  */

  catch(rejectFn) {

    //不是函數(shù)直接返回

    if(!(rejectFn instanceof Function)) {

      return

    }

    if(this.status === STATUS.PENDING) {  

      this.onRejectedList.push(() => {

        // 沒(méi)有錯(cuò)誤信息則不執(zhí)行catch中的函數(shù)

        if(this.rejectData !== null) {

          rejectFn(this.rejectData)

        } 

      })

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

      // 沒(méi)有錯(cuò)誤信息則不執(zhí)行catch中的函數(shù)

      if(this.rejectData !== null) {

        rejectFn(this.rejectData)

      }    

    }      

  }

  /**

  * resolve方法,

  * value為promise直接返回返回一個(gè)以value為resolveData的完成態(tài)promise

  * @param {*} value 

  */

  static resolve(value) {

    if(value instanceof Promise) {

      return value

    }

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

      resolve(value)

    })

  }

  /**

  * reject方法淋淀,類(lèi)似resolve方法

  * @param {*} value 

  */

  static reject(value) {

    if(value instanceof Promise) {

      return value

    }

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

      reject(value)

    })

  }

  /**

  * all方法遥昧,返回一個(gè)新的promise

  * 參數(shù)為promise數(shù)組

  * 成功的時(shí)候返回的是一個(gè)結(jié)果數(shù)組,而失敗的時(shí)候則返回最先被reject失敗狀態(tài)的值朵纷。

  * @param {*} promiseArray

  */

  static all(promiseArray) {

    if(!(promiseArray instanceof Array)) {

      throw new TypeError("parameter must be array")

    }

    let result = []

    let i = 0

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

      if(promiseArray.length === 0) {

        resolve(result)

      } else {

        promiseArray.forEach((item, index) => {

          if(item instanceof Promise) {

            item.then(res => {

              result[index] = res

              i++

              if(i === promiseArray.length) {

                resolve(result)

              }

            }, err => {

              reject(err)

            })

          } 

          // 如果傳入的不是promise炭臭,則直接作為結(jié)果填入結(jié)果數(shù)組中

          else {

            result[index] = item

            i++

            if(i === promiseArray.length) {

              resolve(result)

            }

          }

        })

      }

    })  

  }

  /**

  * race方法,返回一個(gè)新的promise

  * 參數(shù)為promise數(shù)組

  * 返回最先執(zhí)行完的promise的結(jié)果袍辞,不論resolve還是reject

  * @param {*} promiseArray 

  */

  static race(promiseArray) {

    if(!(promiseArray instanceof Array)) {

      throw new TypeError("parameter must be array")

    }

    // 標(biāo)識(shí)符鞋仍,有一個(gè)promise執(zhí)行完成設(shè)為true,返回結(jié)果

    let flag = false

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

      promiseArray.forEach((item) => {

        if(item instanceof Promise) {

          item.then(res => {

            if(!flag) {

              flag = true

              resolve(res)

            }

          }, err => {

            if(!flag) {

              flag = true

              reject(err)

            }          

          })

        } 

        // 如果傳入的不是promise搅吁,則直接作為結(jié)果

        else {

          if(!flag) {

            flag = true

            resolve(item)

          }

        }

      })

    })

  }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

  • 序言:七十年代末威创,一起剝皮案震驚了整個(gè)濱河市落午,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肚豺,老刑警劉巖溃斋,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異吸申,居然都是意外死亡梗劫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)截碴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)梳侨,“玉大人,你說(shuō)我怎么就攤上這事日丹∽卟福” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵哲虾,是天一觀的道長(zhǎng)丙躏。 經(jīng)常有香客問(wèn)我,道長(zhǎng)妒牙,這世上最難降的妖魔是什么彼哼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任对妄,我火速辦了婚禮湘今,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剪菱。我一直安慰自己摩瞎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布孝常。 她就那樣靜靜地躺著旗们,像睡著了一般。 火紅的嫁衣襯著肌膚如雪构灸。 梳的紋絲不亂的頭發(fā)上上渴,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音喜颁,去河邊找鬼稠氮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛半开,可吹牛的內(nèi)容都是我干的隔披。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寂拆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奢米!你這毒婦竟也來(lái)了抓韩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鬓长,失蹤者是張志新(化名)和其女友劉穎谒拴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體涉波,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彪薛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怠蹂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片善延。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖城侧,靈堂內(nèi)的尸體忽然破棺而出易遣,到底是詐尸還是另有隱情,我是刑警寧澤嫌佑,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布豆茫,位于F島的核電站,受9級(jí)特大地震影響屋摇,放射性物質(zhì)發(fā)生泄漏揩魂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一炮温、第九天 我趴在偏房一處隱蔽的房頂上張望火脉。 院中可真熱鬧,春花似錦柒啤、人聲如沸倦挂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)方援。三九已至,卻和暖如春涛癌,著一層夾襖步出監(jiān)牢的瞬間犯戏,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工拳话, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留先匪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓假颇,卻偏偏與公主長(zhǎng)得像胚鸯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子笨鸡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 這是一片陌生的神奇天空 天空下面熙熙攘攘的生命 生命里一個(gè)無(wú)所謂的人 說(shuō)到底姜钳,我還是很不屬于城市的那類(lèi)人 這里的樓...
    rollingstarky閱讀 303評(píng)論 1 2
  • 很多時(shí)候我們喜歡自我設(shè)限:恐懼英語(yǔ)哥桥、恐懼拜訪陌生客戶(hù)辙浑、恐懼上講臺(tái)分享等等,其實(shí)種種恐懼皆因我們自我設(shè)限拟糕,不能真實(shí)面...
    阿幸愛(ài)讀書(shū)閱讀 329評(píng)論 0 0
  • 從無(wú)話(huà)不說(shuō)到無(wú)話(huà)可說(shuō)
    風(fēng)中飛絮fzfx閱讀 170評(píng)論 0 1
  • 前面我們講了什么是信仰今天我們來(lái)講一講什么是迷信宗教信仰是否屬于迷信迷信簡(jiǎn)單來(lái)講就是盲目的相信和崇拜從這個(gè)定義我們...
    育卿閱讀 522評(píng)論 0 0