基於《JS-非同步函式鏈式呼叫》使用起來不是很方便直觀,對此做一次優化,更符合使用的精簡版:
//原始碼
function simpleChainedFn(){
var localParam = arguments; //當前入參
var firstFnArguments; //首節點的入參(陣列格式)
var chainLength = localParam.length; //除掉首節點入參,所有鏈條長度
// 入引數據校驗...
for(i=0;i<localParam.length;i++){
if(!localParam[i] || typeof localParam[i] !== "function"){
// 如果當前是倒是第二個,則認為是首節點的入參;鏈條長度減1...
if(i === localParam.length - 1){
firstFnArguments = localParam[i];
chainLength -= 1;
}else{
console.log("【error】鏈條引數有誤!");
return;
}
}
}
// 組合鏈條...
var firstFn = (function combinationFn(index){
var curFnIndex = index || 0; //當前函式索引
var callBack; //當前函式引數回撥
// 如果存在下一條,則將下一條繫結為當前的回撥...
if(curFnIndex + 1 < chainLength){
callBack = arguments.callee(curFnIndex + 1);
}
var curFn = localParam[curFnIndex];
if(curFn){
if(callBack){
curFn.callback = callBack;
}
return curFn;
}else{
return false;
}
})();
// 啟動鏈條 ...
if(typeof firstFn === "function"){
var suctnParam = "";
if(firstFnArguments){
for(var i = 0 ; i < firstFnArguments.length; i ++)
{
suctnParam += "firstFnArguments[" + i + "]" + (i === firstFnArguments.length - 1 ? "" : ",");
}
}
eval("firstFn(" + suctnParam + ")");
}
}
// 獲取回撥函式
function getCallbackFn(){
return this.callback;
}
鏈條模板:
simpleChainedFn(函式1,函式2,....,函式n,[首節點入參1,首節點入參2,...首節點入參n]);
模板說明:
1、支援多個函式自動擴充套件;
2、如果最後一個引數是陣列,則作為首節點呼叫時的入參;
3、首節點入參個數會隨著陣列長度自動擴充套件;
函式模板:
function 函式名(入參1,入參2,...,入參n){
var callback = getCallbackFn.call(arguments.callee);
// TODO...
if(callback && typeof callback === "function"){
callback(入參1,入參2,...,入參n);
}
}
模板說明:
1、"var callback = getCallbackFn.call(arguments.callee);"儘量在函式體前邊;
實際運用
假設現在有3個需要同步執行的函式:fnA,fnB,fnC;
fnA的功能:將基數(入參1),乘上乘積(入參2),結果值和倒數計時(入參3)傳給fnB;
fnB的功能:進入倒數計時,倒數計時結束後,將入參乘上5,然後傳給fnC;
fnC的功能:將引數列印出來;
// 組合鏈式關係 ...
simpleChainedFn(fnA,fnB,fnC,[2,10,5]);
// 將基數(入參1),乘上乘積(入參2),結果值和倒數計時(入參3)傳給fnB...
function fnA(base,multiplier,cDown){
var callback = getCallbackFn.call(arguments.callee);
console.log("【fnA】基數:" + base + ",乘積:" + multiplier + ",倒數計時:" + cDown);
var num = base * multiplier ;
if(callback && typeof callback === "function"){
console.log("【fnA】執行完畢,結果為:" + num + ",準備進入fnB。");
callback(num,cDown); // 等價於fnB
}
}
// 進入倒數計時,倒數計時結束後,將入參乘上5,然後傳給fnC...
function fnB(base,cDown){
var callback = getCallbackFn.call(arguments.callee);
console.log("【fnB】基數:" + base + ",倒數計時:" + cDown);
var countDown = cDown;
var tTout = setInterval(function(){
console.log("【fnB】進入倒數計時 -> " + --countDown + "s");
if(countDown <= 0){
console.log("【fnB】倒計數結束");
countDown = -1;
clearTimeout(tTout);
var num = base * 5;
if(callback && typeof callback === "function"){
console.log("【fnB】執行完畢,結果為:" + num + ",準備進入fnC。");
callback(num);// 等價於fnC
}
}
},1000);
}
// 將引數列印出來;
function fnC(tArg){
var callback = getCallbackFn.call(arguments.callee);
console.log("【fnC】計算結果為:" + tArg);
if(callback && typeof callback === "function"){
callback();
}
}
執行結果:
【FnA】基數:2,乘積:10,倒數計時:5
【FnA】執行完畢,結果為:20,準備進入fnB。
【fnB】基數:20,倒數計時:5
【fnB】進入倒數計時 -> 4s
【fnB】進入倒數計時 -> 3s
【fnB】進入倒數計時 -> 2s
【fnB】進入倒數計時 -> 1s
【fnB】進入倒數計時 -> 0s
【fnB】倒計數結束
【fnB】執行完畢,結果為:100,準備進入fnC。
【fnC】計算結果為:100