手寫Promise(自定義Promise)

首先我們得先理解Promise工作的機制耍群,其實Promise就是一個構(gòu)造函數(shù)

它的內(nèi)部有三個狀態(tài)

  • pending
  • resolved
  • rejected

而想改變這三個狀態(tài)必須要通過resolve()或者reject()這兩個方法,resolve()可以將pending轉(zhuǎn)換為resolved颊艳,rejected()可以將pending轉(zhuǎn)換為rejected投队。并且將得到的數(shù)值存儲在內(nèi)部的data里面祖能。并且這狀態(tài)一旦轉(zhuǎn)換是不可逆的。

Promsie的原型對象含有then蛾洛,catch這兩個方法

  • then這個方法可以接受兩個參數(shù)养铸,一個成功的回調(diào),一個失敗的回調(diào)轧膘。也就是onResolved和onRejected
  • catch這個方法只可以接受一個參數(shù)钞螟,失敗的回調(diào),也就是onRejected
  • 并且then這個方法谎碍,是返回一個新的promise對象鳞滨,它里面的執(zhí)行方法也是異步的
  • 觸發(fā)then的時候,也會有三個可能蟆淀,一個是狀態(tài)為resolved時拯啦,一個是狀態(tài)為rejected時澡匪,一個是狀態(tài)為pending時
  • Promise的結(jié)果根據(jù)執(zhí)行的結(jié)果返回

然后就可以開始自定義實現(xiàn)Promise了

一、大致框架列出來

  • Promise函數(shù)會接受一個構(gòu)造器褒链,也就是接受一個函數(shù)唁情,我們就命名為executor,executor會調(diào)用resolve和reject甫匹,所以我們就可以寫resolve和reject這兩個方法
  • 定義pending,resolved,rejected甸鸟。因為后面會多處用到,避免書寫錯誤兵迅,導致出現(xiàn)不必要的BUG
  • 內(nèi)部存儲狀態(tài)抢韭,和數(shù)據(jù),初始狀態(tài)為pending恍箭,初始值為undefind
  • Promise原型鏈上有then和catch兩個方法
  • Promise函數(shù)對象有resolve,reject,all,race方法
(function () {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function Promise(executor){
     this.status = PENDING
     this.data = undefind
     this.callbacks = []
      resolve = () => {
      }
      reject = () => {
      }
      try {
          executor(resolve, reject)
      } catch (e) {
          reject(e)
      }
     Promise.prototype.then = () => {
     }
     Promise.prototype.catch = () => {
     }
      /*Promise函數(shù)對象的方法*/
     Promise.resolve = function (value) {

     }
     Promise.reject = function (error) {

     }
    /*只有當所有promise成功時才成功*/
     Promise.all = function (promises) {

     }
    /*其結(jié)果由第一個完成的promise決定*/
     Promise.race = function (promises) {
     }
executor(resolve,reject)
}
window.Promise = Promise
})()

二刻恭、寫函數(shù)內(nèi)部resolve/reject方法

  • 我們改變promise對象的狀態(tài)只能通過resolve/reject改變,所以當我們觸發(fā)方法扯夭,首先得改變狀態(tài)吠各,然后存儲值
  • 我們最開始已經(jīng)定義了常量,所以直接用定義的值
  • 因為resolve/reject改變狀態(tài)只能從pending開始勉抓,所以判斷如果狀態(tài)不是pending的時候,就不用執(zhí)行下面代碼了候学。
resolve = (value) => {
    if(this.satus !== PENDING){
       return
    }
    this.status = RESOLVED
    this.data = value
   if (this.callbacks.length > 0) {
                setTimeout(() => {
                    this.callbacks.forEach(callbacksObj => {
                        callbacksObj.onResolved(value)
                    })
                })
            }
}
reject = (error) => {
    if(this.satus !== PENDING){
       return
    }
    this.status = REJECTED
    this.data = error
   if (this.callbacks.length > 0) {
                setTimeout(() => {
                    this.callbacks.forEach(callbacksObj => {
                        callbacksObj.onRejected(error)
                    })
                })
            }
}

三藕筋、重頭戲開始,寫原型對象then方法梳码,Promise的結(jié)果根據(jù)執(zhí)行的結(jié)果返回

  • 當我們調(diào)用then的時候隐圾,會傳入兩個回調(diào)函數(shù)
  • then方法返回的是一個新的promise對象
  • 我們調(diào)用then時需要考慮三個結(jié)果,也就是當前狀態(tài)為pending時掰茶,為resolved時暇藏,為rejected時
  • then里面所執(zhí)行的方法是異步的
  • 定義一個公共方法handle,減少代碼冗余性
  • 當我們調(diào)用handle函數(shù)也要考慮三種情況濒蒋,因為promise的結(jié)果是根據(jù)執(zhí)行的結(jié)果返回
Promise.prototype.then = (onResolved,onRejected) => {
   return new Promise((resolve,reject) => {
      function handle(callback){
           /*  
              1盐碱、如果拋出異常,return的promise就會失敗
                2沪伙、如果回調(diào)函數(shù)返回的不是promise瓮顽,return就會成功
                 3、如果回調(diào)函數(shù)返回的是promise,return的promise結(jié)果就是這個promise的結(jié)果
           */
            try {
               const result = callback(self.data)
               if (result instanceof Promise) {  //instanceof 運算符用來檢測 Promise.prototype 是否存在于參數(shù) result 的原型鏈
                    result.then(
                          value => {resolve(value)},
                           error => {reject(error)},
                     )
                            //result.then(resolve, reject)
                     } else {
                           resolve(result)
                     }
                     } catch (e) {
                        reject(e)
                     }
      }

      if(this.status === PENDING){
                 this.callbacks.push({
                        onResolved: () => {
                            handle(onResolved)
                        },
                        onRejected: () => {
                            handle(onRejected)
                        }
                    })
      } else if(this.status === RESOLVED){
          setTimeout(() => {
              handle(onRejected)
          })
      } else if(this.status === REJECTED){
          setTimeout(() => {
              handle(onResolved)
          })
      }
   })
}

四围橡、寫原型對象catch方法

 Promise.prototype.catch = function (onRejected) {
            return this.then(undefined,onRejected)
        }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暖混,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翁授,更是在濱河造成了極大的恐慌拣播,老刑警劉巖晾咪,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贮配,居然都是意外死亡谍倦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進店門牧嫉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剂跟,“玉大人,你說我怎么就攤上這事酣藻〔芮ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵辽剧,是天一觀的道長送淆。 經(jīng)常有香客問我,道長怕轿,這世上最難降的妖魔是什么偷崩? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮撞羽,結(jié)果婚禮上阐斜,老公的妹妹穿的比我還像新娘。我一直安慰自己诀紊,他們只是感情好谒出,可當我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邻奠,像睡著了一般笤喳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碌宴,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天杀狡,我揣著相機與錄音,去河邊找鬼贰镣。 笑死呜象,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的碑隆。 我是一名探鬼主播董朝,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼干跛!你這毒婦竟也來了子姜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哥捕,沒想到半個月后牧抽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡遥赚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年扬舒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凫佛。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡讲坎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出愧薛,到底是詐尸還是另有隱情晨炕,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布毫炉,位于F島的核電站瓮栗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瞄勾。R本人自食惡果不足惜费奸,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望进陡。 院中可真熱鬧愿阐,春花似錦、人聲如沸趾疚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盗蟆。三九已至,卻和暖如春舒裤,著一層夾襖步出監(jiān)牢的瞬間喳资,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工腾供, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仆邓,地道東北人。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓伴鳖,卻偏偏與公主長得像节值,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子榜聂,可洞房花燭夜當晚...
    茶點故事閱讀 45,585評論 2 359