1. 程式人生 > >寫一個 符合 promise A+ 規範的 建構函式 MyPromise

寫一個 符合 promise A+ 規範的 建構函式 MyPromise

promise A+規範

promise 是js 非同步發展至今的一個時代的產物  js的非同步 經過如下歷程,  事件監聽  回撥函式  訂閱釋出 

promise 是一個時下非同步 的一個解決方案   其核心設計思想主要概括為以下幾點

1:所涉及到的設計模式 : 訂閱釋出模式(觀察者模式 ) 狀態模式

2 :事件迴圈

promise 中的 三個狀態分別為

  1. pending   //進行中
  2.  fulfilled  //成功
  3. rejected  //失敗

狀態只能從pending 轉為fulfilled 或者rejected  此為promise  守護的三個狀態   (狀態模式)

因為涉及到非同步呼叫 其實promise還是用的訂閱釋出的原理 來解決非同步這一問題  

即 一個成功時的任務佇列  失敗時的任務佇列 

私有方法  resolve 和reject 充當的角色為 改變狀態任務訂閱 

原型方法  then 方法負責根據當前狀態來進行相應的邏輯處理 

promise A+ 規範中 非同步可以基於setTimeout 和process  區別就是在事件迴圈中所處的位置   setTimeout 在處於巨集任務 process 處

於微任務中 注:( ES6中的promise 處於微任務中 此處我們用setTimeout 方式實現 )

 具體程式碼如下 :



const PENDING = "pending"; //進行中
const FULFILLED = "fulfilled"; //成功
const REJECTED = "rejected"; //失敗
function MyPromise(executor){

	let self = this; //快取當前promise 的例項
	self.status = PENDING;
	//成功回撥任務佇列
	self.onResolvedCallbacks = [];
	//失敗回撥的任務佇列。
	self.onRejectedCallbacks = [];

	//當呼叫此方法的時候如果promise 狀態為pending 可以轉成成功態
	//   如果已經是成功態或者失敗態則什麼都不做
	function resolve(value){
		if (value instanceof Promise) {
	      return value.then(resolve, reject)
	    }
	    setTimeout(function(){ // 非同步執行所有的回撥函式  
			if(self.status==PENDING){
				self.status=FULFILLED;
				self.value = value; //成功後會有一個不可變的值 
				self.onResolvedCallbacks.forEach(cb=>cb(self.value));
			}
		})
	}

	function reject(reason){
		setTimeout(function(){ // 非同步執行所有的回撥函式
			if(self.status==PENDING){
				self.status=REJECTED;
				self.value = reason;
				self.onRejectedCallbacks.forEach(cb=>cb(self.value));
			}
		})
	}

	try{
		//此函式可能會異常 所以需要捕獲。 如果出錯了 需要用reject掉當前promise
		executor(resolve,reject);
	}catch(err){
		reject(err)
	}
}

MyPromise.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;
   //如果當前的promise 狀態已經是陳成功態了。onFulfilled 直接值
   if(self.status===FULFILLED){
   	  return promise2 = new MyPromise(function(resolve,reject){
   	  	setTimeout(function(){ // 非同步執行所有onFulfilled
	   	  	try{
	   	  		let x = onFulfilled(self.value);
	   	  		resolvePromise(promise2,x,resolve,reject)
	   	  	}catch(err){
	   	  		reject(err);
	   	  	}
	   	 })
   	  })
   }
   if(self.status === REJECTED){
   	    return promise2 = new MyPromise(function(resolve,reject){
   	    	setTimeout(function(){ // 非同步執行所有onRejected
	   	  	  try{
	   	  		 let x = onRejected(self.value);
	   	  		 resolvePromise(promise2,x,resolve,reject)
	   	  	   }catch(err){
	   	  		 reject(err);
	   	  	   }
	   	  	})
   	    })
   	  
   }
   if(self.status===PENDING){
   	promise2 = new MyPromise(function(resolve,reject){
   	  self.onResolvedCallbacks.push(function(){
   	  	let x = onFulfilled(self.value);
   	  	resolvePromise(promise2,x,resolve,reject)

   	  })
   	  self.onRejectedCallbacks.push(function(){
   	  	let x = onRejected(self.value);
   	  	resolvePromise(promise2,x,resolve,reject)
   	  })
   	})
   }
}

function resolvePromise(promise2, x, resolve, reject) {
  var then
  var thenCalledOrThrow = false

  if (promise2 === x) { // 對應標準2.3.1節
    return reject(new TypeError('Chaining cycle detected for promise!'))
  }

  if (x instanceof Promise) { // 對應標準2.3.2節
    // 如果x的狀態還沒有確定,那麼它是有可能被一個thenable決定最終狀態和值的
    // 所以這裡需要做一下處理,而不能一概的以為它會被一個“正常”的值resolve
    if (x.status === PENDING) {
      x.then(function(value) {
        resolvePromise(promise2, value, resolve, reject)
      }, reject)
    } else { // 但如果這個Promise的狀態已經確定了,那麼它肯定有一個“正常”的值,而不是一個thenable,所以這裡直接取它的狀態
      x.then(resolve, reject)
    }
    return
  }

  if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { // 2.3.3
    try {

      // 2.3.3.1 因為x.then有可能是一個getter,這種情況下多次讀取就有可能產生副作用
      // 即要判斷它的型別,又要呼叫它,這就是兩次讀取
      then = x.then 
      if (typeof then === 'function') { // 2.3.3.3
        then.call(x, function rs(y) { // 2.3.3.3.1
          if (thenCalledOrThrow) return // 2.3.3.3.3 即這三處誰選執行就以誰的結果為準
          thenCalledOrThrow = true
          return resolvePromise(promise2, y, resolve, reject) // 2.3.3.3.1
        }, function rj(r) { // 2.3.3.3.2
          if (thenCalledOrThrow) return // 2.3.3.3.3 即這三處誰選執行就以誰的結果為準
          thenCalledOrThrow = true
          return reject(r)
        })
      } else { // 2.3.3.4
        resolve(x)
      }
    } catch (e) { // 2.3.3.2
      if (thenCalledOrThrow) return // 2.3.3.3.3 即這三處誰選執行就以誰的結果為準
      thenCalledOrThrow = true
      return reject(e)
    }
  } else { // 2.3.4
    resolve(x)
  }
}

MyPromise.deferred = MyPromise.defer = function() {
  var dfd = {}
  dfd.promise = new MyPromise(function(resolve, reject) {
    dfd.resolve = resolve
    dfd.reject = reject
  })
  return dfd
}

module.exports = MyPromise;