Promise 思考及強化實現

Promise 思考及強化實現

標籤(空格分隔): ES6 Promisejavascript


本文原創,如需轉載請註明出處前端

我須要什麼

作了Sudoku項目後,很頭疼的問題就是代碼維護,很大一部分緣由是回調嵌套太多,影響代碼的可讀性,增長了維護難度,尤爲是後端的數據庫操做,用nodeJs一般會寫許多回調嵌套。此次終於打算揭竿起義。java

第二次修改,廢話很少說,直接進入正題
先看下面這段代碼node

function do(){
        //查找數據庫
        setTimeout(()=>{
            console.log('收到數據');
            //修改字段,並保存
            setTimeout(()=>{
                console.log('保存成功')
                //發送響應給前端
            },1000)
            setTimeout
        },1000)
    }
    do()

模擬了很是簡單的一個從前端接受請求到發送響應回到前端的過程,
這個代碼是很是簡單的,不過看起來並非,並且一旦需求更復雜,
這樣風格的代碼確定會讓我很是頭疼es6

我須要的代碼風格

  1. 每一個異步過程獨立成塊,再也不是嵌套風格
  2. 異步返回結果的處理過程獨立於異步過程
  3. 可伸縮,直接擴展異步結果處理過程,並不與以前的混在一塊兒,實現細分,獨立成塊
  4. 每一個異步過程存在依賴

好吧,發現promise知足個人全部需求,拿來現成用?這一點都很差玩
,因此研究了一下promise的用法,下面是我簡易的需求說明數據庫

需求說明(參考ES6的實現效果)

  1. 每一個promise實例 resolve動做 reject動做
  2. promise實例 then方法註冊resolve回調,reject回調
  3. A實例執行完回調,then()會返回一個B實例
  4. B實例跟A同樣,一樣有 resolve動做 reject動做
  5. 調用B的then()方法一樣會註冊resolve回調,reject回調
  6. 影響B動做的因素有4個(下面詳細講解)
  7. 有catch同then同樣,可是隻能註冊一個錯誤回調
  8. a實例如過程上依賴於另一個b實例,則可被當作其resolve參數傳遞,而且b實例成功好事滾粗依賴於 a 的狀態
  9. 一旦實例狀態發生改變,狀態不會再改變

影響B實例的因素

1.A的resolve回調和reject回調是否有異常拋出

是:B執行reject動做 否:B執行resolve動做

2.A的reject動做是否有回調

是:回到1. 、       否:B執行reject動做

3.A的resolve動做是否有回調

是:回到1           否: B執行resolve動做

4.A的回調中return 另外一個promise實例C

C resolve: B resolve    C reject: B reject

具體實現

Promise實例全部的屬性後端

class Promise{
    //構造函數 fn爲構建實例的異步過程
    constructor(fn){
        //必須爲函數類型
		if(typeof fn !== 'function') throw new Error('not a function');
		this.success = [];
		this.sucArg = null;
		this.fail = [];
		this.failArg = null;
		this.state = 0;
		this.parent = null;
		//fork promise分支
		this.fork = [];
		//傳遞的error
		setTimeout(()=>{
			fn(myPromise.resolve.bind(this),myPromise.reject.bind(this))	
		},0);
    }
}

Promise實例的方法,then(),catch()promise

//onFulfilled成功處理函數,onRejected滾粗處理函數
    then(onFulfilled,onRejected){
        /*參數格式限制*/
		let fork = new myPromise(()=>{});
		if(typeof onFulfilled ==='function'){
			this.success.push(onFulfilled);
			fork.forkSuc = onFulfilled;
		}
		if(typeof onRejected ==='function'){
			this.fail.push(onRejected);
			fork.forkRej = onRejected;
		} 
		this.fork.push(fork);
		return fork;
    }
    catch(onRejected){
        //參數必須函數
		let fork = new myPromise(()=>{});
		if(typeof onRejected !=='function') return this;
		this.fail.push(onRejected);
		fork.forkRej = onRejected;	
		this.fork.push(fork);
		return fork;
    }

Promise靜態方法resolve,reject異步

static resolve(value){
        if(this.state!==0) return;
		//參數不是myPromise實例
		if(value instanceof myPromise){
			//如參數是一個promise實例
			value.parent = this;
			if(value.state===1){
				//實例狀態爲成功
				myPromise.resolve.call(this,value.successArg);
			}else if(value.state===-1){
				//實例狀態爲失敗
				myPromise.reject.call(this,value.failArg);
			}
		}else{
			if(!this.success.length){
				for(let fn of this.fork){
					myPromise.resolve.call(fn,value);
				}
			}else{
				this.sucArg = value;
				let cur = 0;
				for(let fn of this.success){	if(this.fork.length&&fn===this.fork[cur].forkSuc){
						let error,preArg,bool;
						try{
							preArg = fn(value);
							if(preArg instanceof myPromise){
								let index = cur;
								bool = true;
								preArg.success.push(()=>{	myPromise.resolve.call(this.fork[index],preArg.sucArg);
								});
								preArg.fail.push(()=>{			myPromise.reject.call(this.fork[index],preArg.failArg);
								})
							}
						}catch(err){
							error = err||null; 
						}
						if(!bool){
							error? myPromise.reject.call(this.fork[cur],error): myPromise.resolve.call(this.fork[cur],preArg);
						}
						cur++;
					}else{
						fn(value);
					}
				}
			}
			//當前promise變爲fulfilled
			this.state = 1;
			//如存在parent,則parent.resolve(value)
			if(this.parent) myPromise.resolve.call(this.parent,value);
		}
    }
    static reject(value){
        if(this.state!==0) return;
		//參數是myPromise實例
		if(value instanceof myPromise){
			value.parent = this;
			myPromise.reject.call(this);
		}else{
			if(!this.fail.length){
				for(let fn of this.fork){
					myPromise.reject.call(fn,value)
				}
			}else{
				this.failArg = value;
				let cur = 0;
				for(let fn of this.fail){
		if(this.fork.length&&fn===this.fork[cur].forkRej){
						let error,preArg,bool;
						try{
							preArg = fn(value);
							if(preArg instanceof myPromise){
								let index = cur;
								bool = true;
								preArg.success.push(()=>{	myPromise.resolve.call(this.fork[index],preArg.sucArg);
								});
								preArg.fail.push(()=>{	myPromise.reject.call(this.fork[index],preArg.failArg);
								})
							}
						}catch(err){
							error = err||null; 
						}
						if(!bool){
							error? myPromise.reject.call(this.fork[cur],error): myPromise.resolve.call(this.fork[cur],preArg);
						}
						cur++;
					}else{
						fn(value);
					}	
				}
			}
			this.state = -1;

			if(this.parent) myPromise.reject.call(this.parent,value);
		}
        
    }

好了,就這麼多,這是個簡易的Promise實現,若有錯誤,或者什麼建議
QQ:387857274歡迎討論函數

相關文章
相關標籤/搜索