JavaScript之Promise實(shí)現(xiàn)

ES2015提出了Promise,同時(shí)基于Promise的異步開(kāi)發(fā)將開(kāi)發(fā)者中回調(diào)地獄中解救出來(lái)。但在沒(méi)有原生支持的環(huán)境下,需要借助Promise/A+之類(lèi)的庫(kù)來(lái)實(shí)現(xiàn)Promise,今天就來(lái)嘗試自行實(shí)現(xiàn)Promise。

1 基本實(shí)現(xiàn)

首先來(lái)完成一個(gè)Promise類(lèi)的基本框架:

function Promise(fn) {
  var resolveCallback = null
  var rejectCallback = null
  
  this.then = function(onResolved, onRejected) {
      resolveCallback = onResolved
      rejectCallback = onRejected
  }
  
  this.resolve = function(value) {
      this.resolveCallback(value)
  }
  
  this.reject = function(reason) {
      this.rejectCallback(reason)
  }
  
  fn(this.resolve, this.reject)
}

以上便是Promise的基本實(shí)現(xiàn)。

2 狀態(tài)管理

上述的代碼存在一個(gè)問(wèn)題,resolve方法會(huì)調(diào)用多次,所以接下來(lái)我們需要接入狀態(tài)管理。

Promise內(nèi)部存在3個(gè)狀態(tài):

  • pending
  • resolved
  • rejected

接下來(lái)在現(xiàn)有代碼之上,加入狀態(tài)管理:

function MyPromise(fn) {
  let state = 'pending'
  var resolveCallback = null
  var rejectCallback = null
  var childResolve
  var childReject
  
  this.then = function(onResolved, onRejected) {
      resolveCallback = onResolved
      rejectCallback = onRejected
  }
  
  this.resolve = function(value) {
      if(state === 'pending') {
         this.resolveCallback(value)
         state = 'resolved' 
      } 
  }
  
  this.reject = function(reason) {
      if(state === 'pending') {
          this.rejectCallback(reason)
          state = 'rejected'
      }   
  }
  
  fn(this.resolve, this.reject)
}

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

上述Promise實(shí)現(xiàn)可以完成正常的異步調(diào)用,但是卻無(wú)法實(shí)現(xiàn)鏈?zhǔn)交卣{(diào),原因在于其then方法沒(méi)有返回一個(gè)新的Promise對(duì)象,所以接下來(lái)還需要改造then方法,實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用:

  this.then = function(onResolved, onRejected) {
      if(state === 'pending') {
        resolveCallback = onResolved
        rejectCallback = onRejected
      }
    
      return new MyPromise((resolve, reject) => {
        ......
      })
  }

光返回一個(gè)promise對(duì)象還沒(méi)用,接下來(lái)我們來(lái)寫(xiě)個(gè)demo測(cè)試下:

  var demo = new MyPromise((resolve, reject) => {
      setTimeout(() => {
          resolve('my first promise')
      }, 1000)
  })

  demo.then((msg) => {
      console.log(msg)
      return 'my second promise'
  }).then((msg) => {
      console.log(msg)
  })

其輸出為:

my first promise

事實(shí)上,第二個(gè)promise對(duì)象的resolve reject方法從未被調(diào)用過(guò),因而其onResolved onRejected的回調(diào)ye就無(wú)從調(diào)用。所以還必須指定時(shí)機(jī)調(diào)用字promise對(duì)象的resolvereject

所以首先需要在創(chuàng)建新promise對(duì)象時(shí),記錄其resolvereject方法:

function MyPromise() {
    ......
    var childResolve
    var childReject
    
      this.then = function(onResolved, onRejected) {
      if(state === 'pending') {
        resolveCallback = onResolved
        rejectCallback = onRejected
      }
    
      return new MyPromise((resolve, reject) => {
        childResolve = resolve
        childReject = reject
      })
  }
}

接下來(lái)還需在resolvereject方法中調(diào)用子對(duì)象的resolvereject方法,整個(gè)Promise完整代碼如下:

function MyPromise(fn) {
    let state = 'pending'
    var resolveCallback = null
    var rejectCallback = null
    var childResolve = null
    var childReject = null
    
    this.then = function(onResolved, onRejected) {
        if(state === 'pending') {
            resolveCallback = onResolved
            rejectCallback = onRejected
        }
      
        return new MyPromise((resolve, reject) => {
            childResolve = resolve
            childReject = reject
        })
    }
    
    this.resolve = function(value) {
        if(state === 'pending') {
            if(resolveCallback) {
                var ret = resolveCallback(value)
                childResolve(ret)
                state = 'resolved' 
            }

        } 
    }
    
    this.reject = function(reason) {
        if(state === 'pending') {
            if(rejectCallback) {
                var ret = rejectCallback(reason)
                childReject(ret)
                state = 'rejected'
            }
        }   
    }
    
    fn(this.resolve, this.reject)
  }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 本文適用的讀者 本文寫(xiě)給有一定Promise使用經(jīng)驗(yàn)的人,如果你還沒(méi)有使用過(guò)Promise,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,444評(píng)論 6 19
  • 你不知道JS:異步 第三章:Promises 在第二章,我們指出了采用回調(diào)來(lái)表達(dá)異步和管理并發(fā)時(shí)的兩種主要不足:缺...
    purple_force閱讀 2,224評(píng)論 0 4
  • JavaScript里通常不建議阻塞主程序,尤其是一些代價(jià)比較昂貴的操作,如查找數(shù)據(jù)庫(kù),下載文件等操作,應(yīng)該用異步...
    張歆琳閱讀 2,820評(píng)論 0 12
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō),Pr...
    雨飛飛雨閱讀 3,484評(píng)論 0 19
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 8,770評(píng)論 0 29

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