JS asynchronous function chain call 2 (simplified version, recommended)

Keywords: Javascript

Be based on JS asynchronous function chain call It's not very convenient and intuitive to use, so it's better to optimize it for the simplified version:

//Source code
function simpleChainedFn(){
    var localParam = arguments; //Current participation
    var firstFnArguments; //Input parameter of the first node (array format)
    var chainLength = localParam.length; //Remove the input parameter of the first node and all chain lengths

    // Input parameter data verification
    for(i=0;i<localParam.length;i++){
        if(!localParam[i] || typeof localParam[i] !== "function"){
            // If it is the second, it is considered as the input parameter of the first node; the chain length is reduced by 1
            if(i === localParam.length - 1){
                firstFnArguments = localParam[i];
                chainLength -= 1;
            }else{
                console.log("[error]Wrong chain parameters!");
                return;
            }

        }
    }

    // Combine chain
    var firstFn = (function combinationFn(index){
        var curFnIndex = index || 0; //Current function index
        var callBack; //Current function parameter callback

        // If the next one exists, bind the next one as the current 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;
        }

    })();

    // Start chain
    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 + ")");

    }
}

// Get callback function
function getCallbackFn(){
    return this.callback;
}

Chain template:

Simplechainedfn (function 1, function 2,..., function n, [first node in parameter 1, first node in parameter 2,... First node in parameter n]);

Template description:
    1. Support automatic extension of multiple functions;
    2. If the last parameter is an array, it is used as the input parameter when the first node is called;
    3. The number of input parameters of the first node will automatically expand with the array length;
    

Function template:

Function function name ({input parameter}){
    var callback = getCallbackFn.call(arguments.callee);

    // TODO...
    

    if(callback && typeof callback === "function"){
        callback({in parameter});
    }

}

Template description:
    1. To avoid closure, "var callback = getcallbackfn. Call (arguments. Call);" should be in front of the function body;    

Practical application
Suppose there are three functions that need to be executed synchronously: fnA, fnB, fnC;
Function of fnA: multiply the cardinality (in parameter 1), product (in parameter 2), and pass the result value and countdown (in parameter 3) to fnB;
Function of fnB: enter the countdown, after the countdown, multiply the input parameter by 5, and then pass it to fnC;
Function of fnC: print out parameters;

// Combined chain relationship
simpleChainedFn(fnA,fnB,fnC,[2,10,5]);




// Pass the radix (in parameter 1), product (in parameter 2), result value and countdown (in parameter 3) to fnB
function fnA(base,multiplier,cDown){
    var callback = getCallbackFn.call(arguments.callee);

    console.log("[fnA]Cardinal number:" + base + ",Product:" + multiplier + ",Count down:" + cDown);
    var num = base * multiplier ;

    if(callback && typeof callback === "function"){
        console.log("[fnA]After execution, the result is:" + num + ",Ready to enter fnB. ");
        callback(num,cDown); // Equivalent to fnB
    }

}

// Enter the countdown, after the countdown, multiply the input parameter by 5, and then pass it to fnC
function fnB(base,cDown){
    var callback = getCallbackFn.call(arguments.callee);

    console.log("[fnB]Cardinal number:" + base + ",Count down:" + cDown);
    var countDown = cDown;
    var tTout = setInterval(function(){
        console.log("[fnB]Enter countdown -> " + --countDown + "s");
        if(countDown <= 0){
            console.log("[fnB]End of countdown");
            countDown = -1;
            clearTimeout(tTout);

            var num = base * 5;

            if(callback && typeof callback === "function"){
                console.log("[fnB]After execution, the result is:" + num + ",Ready to enter fnC. ");
                callback(num);// Equivalent to fnC
            }
        }
    },1000);
}

// Print out the parameters;
function fnC(tArg){
    var callback = getCallbackFn.call(arguments.callee);

    console.log("[fnC]The calculation results are as follows:" + tArg);
    if(callback && typeof callback === "function"){
        callback();
    }

}

Execution result:

[FnA] base: 2, product: 10, Countdown: 5
 [FnA] is completed, the result is: 20, ready to enter fnB.
[fnB] base: 20, Countdown: 5
 [fnB] enter Countdown - > 4S
 [fnB] enter Countdown - > 3S
 [fnB] enter Countdown - > 2S
 [fnB] enter Countdown - > 1s
 [fnB] enter Countdown - > 0s
 [fnB] end of countdown
 [fnB] is completed, the result is: 100, ready to enter fnC.
[fnC] calculation result: 100



Posted by Gregg on Thu, 05 Dec 2019 14:42:56 -0800