你不知道的Promise

最近在掘金上刷面試題的時候不可或非的屢次遇到了Promise的問題,因而經過萬能的搜索引擎,研究一番以後終於對Promise的源碼纔有了一個初步的理解,但願小夥伴能在此獲得一點收穫javascript

你真的懂 promise 的運行機制嗎?

new 一個promise的時候須要傳遞一個執行器函數,當即執行
執行器函數只接受兩個參數 resolve reject
Promise有三個狀態 pedding fulfilled rejectedjava

狀態改變只能由pendding -> fulfilled 或者 pendding -> rejected
狀態一經肯定就沒法改變面試

咱們所瞭解的 then 鏈式調用

Promise 的 then 能夠鏈式調用(返回一個promise對象)
可接收兩個參數(可缺省),一個是成功的回調onFulfilled 一個是失敗的回調onRejected數組

若是成功且有返回值,則若是返回值爲Promise對象則等待promise執行完成
若是成功則走下一個Promise成功的回調不然就走失敗的回調promise

若是返回值是其餘類型則直接做爲下一個then對應的成功或失敗的回調(在成功的回調返回就走下一個then成功的回調,反之亦然)異步

源碼解讀

const PENDDING='pendding';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
function Promise(fn){
   let self = this;
   /**初始化狀態*/
   self.status=PENDDING;
   
   /**保存成功回調函數*/
   self.onFulfilledCallBack=[];
   /**保存失敗的回到數組*/
   self.onRejectedCallBack=[];
   
   /**執行成功回調 */
   function resolve(value){
    if(self.status===PENDDING){
      self.status=FULFILLED;
      self.value=value;
      self.onFulfilledCallBack.forEach(fn=>fn(self.value))
    }
   }
   /**失敗回調*/
   function reject(reason){
     if(self.status===PENDDING){
       self.status=REJECTED;
       self.reason=reason;
       self.onRejectedCallBack.forEach(fn=>fn(self.reason))
     }
   }

   /**當即執行傳入的函數,並加一層捕獲異常 */
   try {
     fn(resolve,reject)
   } catch (error) {
     reject(error)
   }
}


Promise.prototype.then=function(onFulfilled,onRejected){
/**確保用戶在沒有傳入回調函數的時候將值日後傳*/
  onFulfilled = typeof onFulfilled=== "function"?onFulfilled:value=>value;
  onRejected = typeof onRejected=== "function"?onRejected:reason=>{throw reason};
  let self=this;
  let promise2=new Promise(function(resolve,reject){
    if(self.status===FULFILLED){
      try {
      
        /**由於Promise是屬於微任務,因此在這裏須要在外層包裹一個setTimeout 保證它處於異步隊列(關於這個問題的具體緣由能夠百度一下js事件循環機制) */
        setTimeout(()=>{
          let x = onFulfilled(self.value);
          resolvePromise(promise2,x,resolve,reject)
        })
      } catch (error) {
        reject(error)
      }
    }else if(self.status===REJECTED){

      try {
        setTimeout(()=>{
          let x = onRejected(self.reason);
          resolvePromise(promise2,x,resolve,reject)
        })
      } catch (error) {
        reject(error)
      }
    }else if(self.status===PENDDING){
    
    /** 若是在調用then函數的時候promise狀態還處於pendding狀態 則將處理函數分別存入對應的成功或失敗的處理函數數組中 */
    
      self.onFulfilledCallBack.push(()=>setTimeout(()=>{
        try {
          let x = onFulfilled(self.value);
          resolvePromise(promise2,x,resolve,reject)
        } catch (error) {
          reject(error)
        }
      }))

      self.onRejectedCallBack.push(()=>setTimeout(()=>{
        try {
          let x = onRejected(self.reason);
          resolvePromise(promise2,x,resolve,reject)
        } catch (error) {
          reject(error)
        }
      }))
    }
  })
  return promise2;
}

/**處理在then函數中返回值*/
function resolvePromise(promise2,x,resolve,reject){
/**確保只執行一次*/
  let used;
  
  /**若是出現傳入的x==promise2 則會出現死循環,爲了爲了不這種狀況應該在這裏加一層判斷 */
  if(x==promise2){
    reject(new TypeError('Chaining cycle'));
  }else if(x &&typeof x==='function'||typeof x==='object'){
    try {
      let then = x.then;
      
      /**在這裏加上一層判斷是爲了不用戶傳入像{then:""}的對象*/
      if(typeof then==='function'){
        then.call(x,(y)=>{
          if(used)return;
          used=true;
          resolvePromise(promise2, y, resolve, reject);
        },e=>{
          if(used)return;
          used=true;
          reject(e)
        })
      }else{
        if(used)return;
        used=true;
        resolve(x)
      }
    } catch (error) {
      reject(error)
    }
  }else{
    x&&resolve(x)
  }
}
module.exports=Promise
複製代碼

能夠參考這位大佬的文章
小邵教你玩轉promise函數

相關文章
相關標籤/搜索