JS實現Promise原理


promise是用來解決Js中的異步問題的,js中所有的異步可從callback → promise → generator + co = async + await

其實所有的都是callback的變相處理,只是后者慢慢變的越來越優雅和強壯可擴展。

那么如何實現promise呢?先觀察一下promise的樣子

let  a = new Promise((resolve,reject)=>{ // dosomething
 resolve() })

無非是一個名稱叫Promise的對象,然后傳參一個函數 (resolve,reject)=>{resolve()}

promise的強大之處在於回調處理,promise.then(resolveFunticon,rejectFunction)

第一個函數是resolve的回調處理函數,第二個是reject

說到resovle,reject,那么還得再提一下pending,promise對象內部有以上三種狀態。默認是pending狀態

狀態的轉變需要我們手動自己去調用函數resolve()或者reject()

整理一下思路:new promise的時候callback作為傳參參數執行promise函數,callback在promise函數內部執行。callback里手動調用的resolve或者reject方法,那么promise對象里肯定是有這兩種方法的。

最關鍵的是記住狀態,然后再then的時候根據狀態去判斷到底是執行resolveFunticon還是rejectFunction。

function PromiseFn(callBack){ let self = this; self.resolveVal = undefined; self.rejectVal = undefined; self.status = 'pending'//默認是等待狀態
        
        function resolve(val){ if(self.status === 'pending'){ self.resolveVal = val; self.status = 'resolve' } } function reject(val){ if(self.status === 'pending'){ self.rejectVal = val; self.status = 'reject' } }
     //這里要注意,try catch若是寫在 let self = this 會報錯,let存在暫時死區,沒有常規的變量提升。必須先申明后使用
     // callback執行,調用resolve函數。
try{ callBack(resolve,reject)//callback進來自動執行 }catch(e){ reject()//若是有報錯,則直接變為reject狀態 } }

上面關於let的深入可以去看這篇博客:我用了兩個月的時候才理解let

可能會被callback給弄得有點懵,其實把它當做函數fn就行,fn在promise內部執行,然后fn內部剛好有個resolve(),然后再去調用promise的這個resolve執行。

也就是這個原因,所以callback的參數必須是resolve和reject。

上面這一步,需要注意的是callback是立即執行的。下面這段會立即打印111

let  a = new Promise((resolve,reject)=>{
       console.log('111')
})
console.log('456')

上面我們定義了 resolveVal 和 rejectVal,因為待會在promise調用then執行的時候,會作為參數傳參給resolveFunticon或者rejectFunction

所以promise對象內部必須記住這個參數。

下面一起看看promise.then吧,promise.then(resolveFunticon,rejectFunction)。在promise的原型鏈上有個then方法

PromiseFn.prototype.then = function(resolveFunction,rejectFunction){
  let self = this;
  if(self.status === 'resolve'){
	resolveFunction(self.resolveVal)
  }
  if(self.status === 'reject'){
	rejectFunction(self.rejectVal)
  }
}

在then執行的時候,去判斷內部是啥狀態,然后執行對應的resolve或者reject回調函數。  

然后運行試一試

let promiseA = new PromiseFn((resolve,reject)=>{
         resolve('成功啦')
})
promiseA.then((resolveVal)=>{
	console.log('resolve'+resolveVal)
},(rejectVal)=>{
	console.log('reject'+rejectVal)
})

結果是:  

但是這樣就結束了嗎?no,我們一般對Promise的使用場景可能是下面這樣的,需要考慮異步問題。

let promiseA = new PromiseFn((resolve,reject)=>{
	setTimeout(function(){
		resolve('成功啦')
	},2000)
})

這里用settimeout代替一下,一般我們都是一個ajax請求,然后在請求到結果后去resolve.

上面的寫法顯然是無法滿足這種條件的,當去執行promise.then的時候,發現狀態還是pending,不做任何執行。

那我們怎么去做呢?發現狀態是pending,肯定是兩秒鍾之內啦,不妨先把promise.then兩個函數參數先在promise里面記下來,兩秒鍾后狀態變為resolve了,再執行函數。

      function PromiseFn(callBack){
		try{
			callBack(resolve,reject)
		}catch(e){
			reject()
		}
		let self = this;
		self.resolveVal = undefined;
		self.rejectVal = undefined;
		self.status = 'pending'//默認是等待狀態
		self.keepResolveFn = []//
		self.keepRejectFn = []//
		
		function resolve(val){
			if(self.status === 'pending'){
				self.resolveVal = val;
				self.status = 'resolve';
				self.keepResolveFn.forEach(fn=>fn());
			}
		}
		function reject(val){
			if(self.status === 'pending'){
				self.rejectVal = val;
				self.status = 'reject';
				self.keepRejectFn.forEach(fn=>fn());
			}
		}
		//執行先記錄resolve和reject函數事件
		
	}
	PromiseFn.prototype.then = function(resolveFunction,rejectFunction){
		let self = this;
		if(self.status === 'resolve'){
			resolveFunction(self.resolveVal)
		}
		if(self.status === 'reject'){
			rejectFunction(self.rejectVal)
		}
		if(self.status === 'pending'){
			self.keepResolveFn.push(()=>{
				resolveFunction(self.resolveVal);
        	});
        	self.keepRejectFn.push(()=>{
            	rejectFunction(self.rejectVal)
        	});
		}
	}
	let promiseA = new PromiseFn((resolve,reject)=>{
		setTimeout(function(){
			resolve('成功啦')
		},2000)
	})
	promiseA.then((resolveVal)=>{
		console.log('resolve'+resolveVal)
	},(rejectVal)=>{
		console.log('reject'+rejectVal)
	})

結果是:延遲兩秒后,打印出  ‘resolve成功啦’。

最后多提一句:所有的then方法執行,也是通過return 一個新的promise對象來執行的。這樣才有鏈式回調,new promise.then().then().then()

        var b = 10;
        new Promise((resolve, reject) => {

            setTimeout(() => {
                b += 10;
                resolve();
//                reject();
            }, 1000);

        }).then(function() {
            console.log(b);
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    b *= 2;
                    resolve();
                }, 1000);
            });
        }).then(function() {
            console.log(b);
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    b *= b;
                    resolve();
                }, 1000);
            });
        }).then(function() {
            console.log(b);
        },function() {
            console.log('失敗了');
        });

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM