ES6僞順序代碼執行的實現(類似同步阻塞,但不會導致頁面卡死)

最近在寫前臺,想起曾經被回調地獄支配的恐懼,希望能找到徹底摒棄回調函數的辦法。然後我去翻了一下ES6的新特性(emm...貌似已經不是新特性了?)遺憾的是,我並沒有找到現成的辦法。

不過,通過ES6所帶來的yield語法,這一點完全可以做到,下面造了個輪子提供一個實現:

function syn(func) {
	let method = {}
	let gt = func.call(func, method);
	method.exc = function() {
		let target = arguments[0];
		let args = [];
		for(let i=1; i<arguments.length; i++) {
			if(func==arguments[i]) {
				args.push(function(){
					gt.next(arguments);
				});
			} else {
				args.push(arguments[i]);
			}
		}
		target.apply(func, args);
	};
	gt.next();
}

十分簡短的代碼,但是足以實現我們的目的。事實上,出於便捷考慮,我們完全可以在函數內多定義一些常用的回調方法,比如require或onevent,當然也可以通過new的參數去動態增加,這些都十分容易實現,在此不多贅述。

下面我們先看一下如何來使用:

我們先定義一個callback函數,出於簡潔性考慮,這裏我用計時器的回調來模擬。然後new syn()實現函數的運行。

我們可以寫任意多個var val = yield method.exc();一定當上一個過程完成後纔會開始下一個過程,此時可以確保回調過程已經發生。在下面,我們用this來表達回調函數的書寫位置,用1,2,3來模擬回調函數的參數,在進行web請求的情況下,這應該是請求的結果。

該書寫形式只支持一個回調函數,顯然對於web請求來說只有success時才應該繼續下面的代碼,如果失敗,應當考慮用捕獲異常的方式去結束這段代碼。當然,如果你十分渴望對多回調的支持,那也並不難實現。

new syn(function*(method){
	let param = yield method.exc(callback, "a", "b", this);
	console.log(param[0]+","+param[1]+","+param[2]);
});

function callback(opt1, opt2, func) {
	console.log(opt1+","+opt2);
	setTimeout(func, 1000, "1", "2", "3");
}

注意到,我們唯一的縮進就是new syn,將函數定義爲function*,這樣對它的執行將返回一個迭代器,這個迭代器本質上是一組被yield語法切割的函數組合,也就是ES6提供的語法糖。每一個yield執行完成時都將返回一組新的參數,這組參數由gt.next提供。

回調函數也有一大堆參數,只不過這堆參數是以參數列表的形式寫上去的,既然這樣,我們完全可以接管回調函數,並且把回調函數的參數列轉移給gt.next,使gt.next擁有一個連貫的上下文。這也就是上述實現的核心思想。

顯而易見的,這個實現有一個缺點,那就是原本可以並行執行的過程將被迫變成順序執行,從而浪費時間,但從另一個角度來說,這也是順序執行代碼所必要的特點。

以上就是全部內容,感謝您的關注,我們下期有約【什麼,我沒上電視?】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章