基於《JS-異步函數鏈式調用》使用起來不是很方便直觀,對此作一次優化,更符合使用的精簡版:segmentfault
//源碼 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]); 模板說明: 一、支持多個函數自動擴展; 二、若是最後一個參數是數組,則做爲首節點調用時的入參; 三、首節點入參個數會隨着數組長度自動擴展;
函數模板:異步
function 函數名(入參1,入參2,...,入參n){ var callback = getCallbackFn.call(arguments.callee); // TODO... if(callback && typeof callback === "function"){ callback(入參1,入參2,...,入參n); } } 模板說明: 一、"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