手寫promise的幾個核心概念

核心概念和流程

promise有幾個重要的概念,只要弄明白這幾點,基本上就能夠實現大體的框架了git

  • promise中有三種狀態,pendingfulfilledrejected
  • 每個promise一旦resolve,他的狀態立刻變成fulfilled,再執行本身的onResolve函數後,resolve下一個promise,依次類推
  • then接收onResolveonReject做爲參數,若是這兩個函數返回值爲promise,則要等待這個promise,若是返回值不是promise,則將這個返回值傳遞給下一個promise
  • then會返回一個promise對象

測試函數

首先寫一些主要的測試代碼github

<!-- 異步 -->
new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('executor')
    resolve(1)
  }, 1000)
})
.then(value => {
  console.log('then1', value)
  return 2
})
.then(value => {
  console.log('then2', value)
})
複製代碼
<!-- 同步 -->
new Promise((resolve, reject) => {
  console.log('executor')
  resolve(1)
})
.then(value => {
  console.log('then1', value)
  return 2
})
.then(value => {
  console.log('then2', value)
})
複製代碼
<!-- 同步 異步 嵌套promise -->
new Promise((resolve, reject) => {
  console.log('外部promise')
  resolve(1)
})
.then(value => {
  console.log('外部then1', value)
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('內部promise')
      resolve(2)
    }, 1000)
  })
  .then(value => {
    console.log('內部then1', value);
    return 3
  })
  .then(value => {
    console.log('內部then2', value);
    return 4
  })
})
.then(value => {
  console.log('外部then2', value);
})
複製代碼

實現executor

第一步確定是實現new Promise(executor)的寫法,調用promise的構造函數,傳入一個參數爲resolvereject的函數,並當即執行promise

constructor(executor) {
  this.state = "pending";
  this.value = undefined;
  this.reason = undefined;
  this.resolveCallbacks = []
  this.nextPromise = undefined
  if (executor && typeof executor === "function") {
    executor(this.resolve.bind(this), this.reject.bind(this));
  }
}
複製代碼

實現resolve

  • resolve接受一個value,而且改變promise的狀態
  • resolve改變狀態後,執行本身的onResolve回調
  • 執行下一個promiseresolve,其中還要判斷onResolve返回的是否爲promise對象,是的話要等待這個promise
resolve(value) {
  if (this.state === "pending") {
    this.state = "fulfilled"
    this.value = value
    if (this.resolveCallbacks.length) {
      // 調用then中註冊的onResolve回調
      while(this.resolveCallbacks.length) {
        const onResolve = this.resolveCallbacks.pop()
        const result = onResolve(value)
        if (result instance of Promise) {
          // 若是是promise對象,調用這個promise的then
          result.then(v => {
            this.nextPromise && this.nextPromise.resolve(value)
          })
        } else {
          this.nextPromise && this.nextPromise.resolve(value)
        }
      }
    } else {
      // 沒有的話就執行下一個promise的回調
      this.nextPromise && this.nextPromise.resolve(value)
    }
    
  }
}
複製代碼

實現then

  • 若是狀態已是fulfilled,這個時候就立刻執行onResolve回調
  • 若是狀態是pending,這個時候要把onResolve存起來
  • then一直會返回一個promise對象
then(onResolve, onReject) {
  let promise = new Promise()
  if (this.state === "fulfilled") {
    // 若是onResolve返回的不是一個promise對象,就返回一個立刻resolve的promise
    // 若是onResolve返回的是promise,就在該promise對象的then裏面resolve
    promise = new Promise((resolve, reject) => {
      if (onResolve && typeof onResolve === "function") {
        const result = onResolve(this.value)
        if (result instanceof Promise) {
          result.then(value => {
            resolve(value)
          })
        } else {
          resolve(result)
        }
      } else {
        resolve(this.value)
      }
    })
  } else if (this.state === "pending") {
    if (onResolve && typeof onResolve === "function") {
      this.resolveCallbacks.push(onResolve)
    }
  }
  this.nextPromise = promise
  return promise
}
複製代碼

待完成

  • thencatch的回調必須放到微任務隊列執行的(window.queueMicrotask或者proess.nextTick),注意不是setTimeout
  • 添加try catchreject,注意catchreject都是異常捕獲,而且發生異常的時候catchreject會按照聲明順序,只執行一個最早聲明的一個
  • 添加靜態方法resolvereject

其餘

  • 完整的代碼能夠參考下面的連接
  • github.com/Leonewu/dai…
  • 寫完以後對eventloopmicroTaskmacroTaskpromise的執行機制的理解都清晰不少了
  • 寫的比較簡潔,歡迎補充^_^

參考

相關文章
相關標籤/搜索