手寫一個符合promise A+規範的promise(上)

背景

js在進行異步操做時,常常會使用promise來獲取異步操做的返回結果,那promise內部到底是如何實現的?api

本文經過手寫一個符合promise A+規範的promise類,來深刻了解promise的實現邏輯。數組

什麼是promise A+規範

promise A+規範,是一個開源的、可被開發者實現的標準promise規範,規定了實現一個標準的promise具體須要實現哪些功能。promise

promise A+規範相關術語:

  1. promise是一個包含了兼容promise規範then方法的對象或函數,
  2. thenable是一個包含了then方法的對象或函數。
  3. value是任何Javascript值。 (包括 undefined, thenable, promise等).
  4. exception是由throw表達式拋出來的值。
  5. reason是一個用於描述Promise被拒絕緣由的值。

須要實現的功能有:

  1. promise狀態,包括:pending, fulfilled或者rejected。
  2. then方法,then方法中包括onFulfilled和onRejected兩個參數。

具體實現功能細則參考:promises A+規範瀏覽器

目前瀏覽器實現的promise,有哪些api呢

大概分爲兩種:異步

一、Class類上的方法

Promise.all, Promise.resolve, Promise.reject, Promise.race函數

二、實例上的方法

then/catch/finally測試

開始實現

咱們平時使用Promise,寫法大概是這樣子:

let promise = new Promise(function(resolve, reject) {
  // 若是作什麼異步操做成功了
  setTimeout(() => {
    let isSuccess = true
    if (isSuccess) {
      resolve('接口返回成功了')
    } else {
      reject('接口返回失敗了')
    }
  }, 1000)
})

promise.then(value => {
  console.log('success', value)
}, error => {
  console.log('error', error)
})

// 日誌打印
// -> 接口返回成功了
複製代碼

那咱們如何實現一個如上功能的promise?

如何實現一個promiseui

能夠看到promise是一個類,裏面傳遞一個帶了resolve和reject參數的函數,這個函數叫作executor執行器,executor中包含了一個resolve函數和一個reject函數。this

具體實現:spa

// 定義promise的三種狀態常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function Promise(executor) {
  // 初始化promise狀態和value值
  let that = this
  that.status = PENDING
  that.value = undefined

  // resolve執行時,將狀態置爲成功態
  function resolve(value) {
    // 只有狀態爲pending時,status修改成fulfilled,同時更新value的值
    if (that.status === PENDING) {
      that.status = FULFILLED
      that.value = value
    }
  }

  // reject執行時,將狀態置爲失敗態
  function reject(reason) {
    if (that.status === PENDING) {
      that.status = REJECTED
      that.value = reason
    }
  }

  executor(resolve, reject)
}

Promise.prototype.then = function(onFulfilled, onRejected) {
  let that = this
  // 若是當前狀態爲已完成,則執行完成的回調
  if (that.status === FULFILLED) {
    onFulfilled(that.value)
  }
  // 若是當前狀態爲已失敗,則執行失敗的回調
  if (that.status === REJECTED) {
    onRejected(that.value)
  }
}
複製代碼

一個簡單的promise實現就已經完成,包含new Promise(executor: (resolve, reject) => void)的實現,而且支持then調用的邏輯來獲取value或者reason。

可是該實現還不支持異步resolve或者reject狀態

給promise添加發布/訂閱者模式來支持異步更新狀態

前面實現的promise,還有一個問題,就是executor執行器裏的resolve若是延遲執行,好比延遲1000ms後再執行,當promise.then優先於resolve或者reject執行,此時該promise的status仍是pending狀態,不會執行then裏面的onFulfilled和onRejected方法

因此這裏咱們要使用發佈/訂閱者模式,將promise.then裏面的onFulfilled和onRejected兩個監聽方法存儲起來,在promise的狀態resolve或者reject時再通知對應的監聽方法

添加發布/訂閱者模式

// 定義promise的三種狀態常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function Promise(executor) {
  // 初始化promise狀態和value值
  let that = this
  that.status = PENDING
  that.value = undefined
  // 初始化訂閱resolve和rejecte方法的回調數組
  that.onFulfilledCallbacks = []
  that.onRejectedCallbacks = []
  // resolve執行時,將狀態置爲成功態
  function resolve(value) {
    // 只有狀態爲pending時,status修改成fulfilled,同時更新value的值
    if (that.status === PENDING) {
      that.status = FULFILLED
      that.value = value

      // 執行訂閱了resolve的回調方法
      that.onFulfilledCallbacks.forEach(onFulfilled => onFulfilled(that.value))
    }
  }

  // reject執行時,將狀態置爲失敗態
  function reject(reason) {
    if (that.status === PENDING) {
      that.status = REJECTED
      that.value = reason
      // 執行訂閱了reject的回調方法
      that.onRejectedCallbacks.forEach(onRejected => onRejected(that.value))
    }
  }

  executor(resolve, reject)
}

Promise.prototype.then = function(onFulfilled, onRejected) {
  let that = this
  // 若是當前狀態爲已完成,則執行完成的回調
  if (that.status === FULFILLED) {
    onFulfilled(that.value)
  }
  // 若是當前狀態爲已失敗,則執行失敗的回調
  if (that.status === REJECTED) {
    onRejected(that.value)
  }
  // 若是當前狀態還在pending,則將回調方法添加到訂閱狀態的回調中
  if (that.status === PENDING) {
    // 訂閱resolve的回調
    that.onFulfilledCallbacks.push(onFulfilled)
    // 訂閱reject的回調
    that.onRejectedCallbacks.push(onRejected)
  }
}
複製代碼

測試

好的,如今咱們實現的promise已經很是強大了,能夠寫一個簡單的測試用例,跑一下。

let promise1 = new Promise(function(resolve, reject) {
  resolve('promise1-直接返回成功')
})

let promise2 = new Promise(function(resolve, reject) {
  setTimeout(() => {
    reject('promise2-異步返回成功')
  }, 1000)
})

let promise3 = new Promise(function(resolve, reject) {
  resolve('promise3-直接返回成功')
  reject('promise3-直接返回失敗')
})

promise1.then((value) => {
  console.log('promise1-執行了onFulfilled', value)
}, (reason) => {
  console.log('promise1-執行了onRejected', reason)
})

promise2.then((value) => {
  console.log('promise2-執行了onFulfilled', value)
}, (reason) => {
  console.log('promise2-執行了onRejected', reason)
})

promise3.then((value) => {
  console.log('promise3-執行了onFulfilled', value)
}, (reason) => {
  console.log('promise3-執行了onRejected', reason)
})

// 執行結果
// -> promise1-執行了onFulfilled promise1-接口返回成功了
// -> promise3-執行了onFulfilled promise3-接口返回成功了
// 1000ms後
// -> promise2-執行了onRejected promise2-異步返回成功
複製代碼

測試結果符合要求

promise1經過resolve,直接觸發then裏的onFulfilled,打印promise1-執行了onFulfilled promise1-接口返回成功了

promise2經過延遲觸發reject,延遲1000ms後觸發了onRejected,打印promise2-執行了onRejected

promise3先resolve再reject,因爲resolve後當前promise狀態會更新爲fulfilled,因此後面再執行reject會無效,直接打印promise3-執行了onFulfilled

總結

目前咱們的promise實現瞭如下功能:

  1. 實現了status狀態,包含pending,fulfilled,rejected三種狀態
  2. 實現了value的屬性,能夠經過then方法傳入onFulfilled和onRejected中
  3. 實現了executor執行器以及裏面的resolve和reject方法
  4. 實現了then方法,當狀態更新爲fulfilled或者rejected時,會將promise的value值傳給then方法裏的onFulfilled和onRejected
  5. 實現了異步更新狀態時,通知then方法裏面的onFulfilled和onRejected

這就是一個簡單的符合promise A+規範promise實現,不過promise還有許多其餘的功能特性和api,好比:Promise.resolve,Promise.reject,Promise.all等,我會在後面的文章中更新。

未完待續...

相關文章
相關標籤/搜索