user965306
user965306

Reputation:

Nesting callbacks

I'm not so experienced in async javascript. How can I call the commands without hardcoding the amount of commands or using eval?

var commands = [
    // command 1: result: 0, stdout: ""
    function (stdin, callback) {
        callback(0, "");
    },
    // command 2: result: 1, stdout: ""
    function (stdin, callback) {
        callback(1, "");
    },
    // command 3: result: 0, stdout: ""
    function (stdin, callback) {
        callback(0, "");
    },
    // ...
];

var stdin = "foo";
var end = function (result, stdout) {
    console.log(result);
    console.log(stdout);
};

commands[0](stdin, function (result, stdout) {
    commands[1](stdout, function (result, stdout) {
        commands[2](stdout, end);
    });
});

Upvotes: 2

Views: 153

Answers (2)

iMoses
iMoses

Reputation: 4348

Final answer:

I'm using recursion to go through the commands array. You pass the loop function an array of commands and the last callback to be called (you can also pass as a fourth optional parameter the index of the array in which you wish to start the loop - defaults to zero).

var commands = [
    // echo foo
    function (stdin, callback) {
        callback(0, "foo");
    },
    // touppercase
    function (stdin, callback) {
        callback(1, stdin.toUpperCase());
    }
];

var stdin   = "",
    loop    = function(commands, lastCallback, stdin, startIndex) {
        (function insideLoop(i, stdout) {
            commands[i](stdout, (i + 1 < commands.length) ? function(result, stdout){ insideLoop(i + 1, stdout); } : lastCallback); 
        })(startIndex || 0, stdin);
    },
    end     = function (result, stdout) {
        console.log(stdout);
    };

loop(commands, end, stdin);

Code Example

Upvotes: 1

jAndy
jAndy

Reputation: 236202

To let those functions run asyncronously, you need a way to invoke them by making sure that inbetween the calls, a browser (or actually any implementation) is allowed to do other stuff and things (cleanups, reflows, etc.).

That can be done with .setTimeout in browsers or .nextTick in nodejS.

function runAsync( list ) {
    (function _worker( method ) {
        method();

        if( list.length ) {
            setTimeout(function() {
                _worker( list.shift() );
            }, 100);
        }
    }( list.shift() ));
}

This would get called like

runAsync( commands );

and it would succesive grab the next array-entry (which is assumed a function) and execute it. After that, we check if there are more elements in that entry and if so, grab the next and call the next function. That happens within a setTimeout call and a delay of 100ms. I choosed 100ms here, because its pretty much the timeframe which human beeings won't see any "slow-down" or "lagging".

Upvotes: 0

Related Questions