Structuring Asynchronous Programs

Having to deal with a flow which requires a lot of async calls nested within each other makes it a cumbersome task to understand the logic easily by just looking at it. Look at the following example to get a basic idea


function somefunction(v1, callback) {
    f1(v1, function (resp1) {
        if (resp1) {
            f2(resp1, function (resp2) {
                f3(resp2, function (resp3) {
                    f5(resp4, function (resp5) {
                        f6(resp5, function (resp6) {
                            callback(resp6);
                        });
                    });
                });
            });
        }
        else {
            f4(v3, function (resp4) {
                callback(resp4);
            });
        }
    });
}

 

the problem becomes double fold when you have functions that are running in sequence mixed with functions that are running as a callback to another function.

The first and foremost thing to do is to split these functions apart into sub-functions so that one function only contains single type of nesting. Ie we either have only nesting statements in a function or sequential statements with one level of nesting. This will help understand the functions a bit more clearly. Take at the following updated code to see this implementation.

function somefunction(v1, callback) {
    f1(v1, function (resp1) {
         somefunction_casecheck(resp1,callack);
    });
}

function somefunction_casecheck(resp1, callback) {
    if (resp1) {
        somefunction_truecase(resp1, callback)
    }
    else {
        somefunction_falsecase(callback);
    }
}

function somefunction_falsecase(callback) {
    f4(v3, function (resp4) {
        callback(resp4);
    });
}

function somefunction_truecase(resp, callback) {
    f2(resp, function (resp2) {
        f3(resp2, function (resp3) {
            f5(resp4, function (resp5) {
                f6(resp5, function (resp6) {
                    callback(resp6);
                });
            });
        });
    });
}

Now, it becomes much easier to read the code but we end up with another problem which is a huge list of functions we have.

The best option to get rid of this huge list of functions is by grouping them. The above code shows grouping by using the main function name as prefix of the sub-function, however that may not always end up being easy to manage with multiple main functions. If you are using plain javascript, you can define functions as variables of an array / object. In other languages you may chose to move them to separate files.

The structure of a library that you are building and is using a lot of nesting will then be like this

the main file will be exposing functions to the external programs and will provide the starting point for the functions. This main file will include references to subfiles, each large function flattened and moved to its own subfile. And lastly one or more helper libraries. The helper library provide common functions used within your program and may need to be included in multiple subfiles. You will end up with following files for one service / package having its own independent folder. Following are the contents of the ‘EXAservice’ folder

[code lang=”html”]

EXAservice.js

functionOne.subfile.js

functionTwo.subfile.js

functionThree.subfile.js

EXAcommon.helper.js

[/code]

This will mean you will end up with much more files but as long as you keep a good directory structure, using a separate sub-folder for a decent service / module / package is not a big concern when compared to the improved code readability you will get.

This will help you reduce the chances of missing conditions that are never called back, resulting in your program hanging waiting for nothing. Make it much easy for you to troubleshoot and make it possible to understand the code at a single glance.

0 Comments

Leave a reply

Your email address will not be published. Required fields are marked *

*