0

I have a complicate recursive javascript function that worked very well until I needed to start using asynchronous functions (jQuery.ajax in this case). I have included some psuedo-code below that gives the gist of the situation. I would like to implement this code using promises (instead of the current callbacks), but can't work out how to do deal with the recursion and the multiple conditional ajax calls. If I understand promises correctly they allow you to act on the return of an asynchronous call, but how do I deal with the situation below?

function wrapperFunction(success,error) {
    var level = 0;
    result = [];

    var innerFunction = function(info,result,success,error) {
        level++;

        jQuery.ajax({
            url: 'baseurl1' + info,
            success: parseData,
            error: error
        });

        function parseData(data) {
            data.forEach( function(item) {
                result.push(item.something);

                if ( item.info ) {
                    innerFunction(item.info, result, success, error);
                }
            });

            if ( data.condition ) {
                jQuery.ajax({
                    url: 'baseurl2' + info,
                    success: parseData2,
                    error: error
                });
            }

            function parseData2(data2) {
                data2.forEach(function(item2) {
                    if ( item2.condition ) {
                        jQuery.ajax({
                            url: 'baseurl3' + info,
                            success: parseData3,
                            error: error
                        });
                    }
                });
                function parseData3(data3) {
                    if ( data3.condition ) {
                        jQuery.ajax({
                            url: 'baseurl4' + info,
                            success: parseData4,
                            error: error
                        });
                    }
                    function parseData4(data) {
                        result.push(data2.something + data4.something);
                    }
                }
            }

            level--;
            if (level == 0 && success) {
                success(result);
            }
        }

    }

    innerFunction('rootinfo', result, success, error);   
}   

wrapperFunction(
    function(data) {
        // process success
    },
    function(err) {
        // handle errors
    }
}

As I said already, this is only pseudo code. I initially extracted it from my real code to see if I could get my head around the actual structure. I know it works if the ajax calls where synchronous, but now they are asynchronous it only sometimes works (depending on how quickly the calls return).

How do I implement this situation using promises?

EDIT

I have just worked out how to use promises to serialise everything, and though that is one way to wait for everything to finish I rather run multiple calls in parallel and then find a way to wait for everything to finish. I know this is possible with promises, but I don't know how.

8
  • Why do you want to use promises? They offer no real benefit over what you currently have. Also note that there is no recursion here. You could probably tidy the code to make it more elegant, but that would depend on the scope required of each function and the data it retrieves. Commented Feb 24, 2016 at 9:18
  • InnerFunction calls an ajax query, which calls parseData on success, which calls innerFunction under certain conditions. That looks like recursion to me. Commented Feb 24, 2016 at 9:24
  • You can do something like this: jsfiddle.net/sandenay/0pa0L9dx Commented Feb 25, 2016 at 6:56
  • This way your AJAX calls would fire in parallel and then we may wait for all promises to resolve Commented Feb 25, 2016 at 6:57
  • @RoryMcCrossan As Chris says the innerFunction is called recusively. As for promises, I somehow need a way to wait for all ajax queries to finish before moving on. If you know of a way to do that without promises, feel free to share. Commented Feb 25, 2016 at 7:51

1 Answer 1

0

I have got it working, with the help of Sandeep Nayak (see comments above). I thought I post the working version of the pseudo code for anyone coming across this post with a similar problem.

I have essentially added two levels of promises (outer and inner), where the outer promise does get resolved if all inner promises are resolved. There is probably scope for tidying up the code, but it works as it stands.

function wrapperFunction(success,error) {
    var level = 0;
    var result = [];
    var outerPromises = [];

    var innerFunction = function(info,result,success,error) {
        var outerPromise = new jQuery.Deferred();
        outerPromises.push( outerPromise );

        level++;

        jQuery.ajax({
            url: 'baseurl1' + info,
            success: parseData,
            error: error
        });

        function parseData(data) {
            data.forEach( function(item) {
                result.push(item.something);

                if ( item.info ) {
                    innerFunction(item.info, result, success, error);
                }
            });

            if ( data.condition ) {
                jQuery.ajax({
                    url: 'baseurl2' + info,
                    success: parseData2,
                    error: error
                });
            } else {
                outerPromise.resolve();
            }

            function parseData2(data2) {
                var innerPromises = [];

                data2.forEach(function(item2) {
                    var innerPromise = new jQuery.Deferred();
                    innerPromises.push( innerPromise );

                    if ( item2.condition ) {
                        jQuery.ajax({
                            url: 'baseurl3' + info,
                            success: parseData3,
                            error: error
                        });
                    } else {
                        innerPromise.resolve();
                    }

                    function parseData3(data3) {
                        if ( data3.condition ) {
                            jQuery.ajax({
                                url: 'baseurl4' + info,
                                success: parseData4,
                                error: error
                            });
                        } else {
                            innerPromise.resolve();
                        }
                        function parseData4(data) {
                            result.push(data2.something + data4.something);

                            innerPromise.resolve();
                        }
                    }
                });

                jQuery.when.apply(undefined, innerPromises).then( function() { outerPromise.resolve(); } );
            }

            level--;
            if (level == 0 && success) {
                jQuery.when.apply(undefined, outerPromises).then( function() { success(result); } );
            }
        }

    }

    innerFunction('rootinfo', result, success, error);   
}   

wrapperFunction(
    function(data) {
        // process success
    },
    function(err) {
        // handle errors
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.