JS-非同步函式鏈式呼叫2(精簡版,推薦)

Lycop發表於2019-02-16

基於《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



相關文章