Search code examples
javascriptajaxasynccallbackevent-driven-design

How to use JS callbacks in a recursive way?


I have this part of the code that doesn't work. It suppose to make a part of a tree view. The callback for the klassification_ajax should work after the function is done, but cause of the other ajax calls in different iteration of the while loop, then it doesn't work at all. I checked If I had just one iteration, it works cause it doesn't interfere with other ajax calls, but when it goes for the second iteration, they happen simultaneously and as the result none of them work. then I realized I should have make those iterations as a nested callback to make it work step by step, but HOW ?????

    var j = 2;
    while (result['klass-' + j]) {
        klass_id = result['klass-' + j];

        if (handled_klass.indexOf(result['klass-' + (j - 1)]) == -1) {
            handled_klass.push(result['klass-' + (j - 1)]);

            klassification_ajax(result['klass-' + (j - 1)], function () {
                $('#all-klassifikation-' + result['klass-' + (j - 1)]).collapse('show');
                $('#klassifikation-' + klass_id).css("font-weight", "Bold");
            });
        }
        else {
            $('#klassifikation-' + klass_id).css("font-weight", "Bold");
        }
        j++;
    }

Solution

  • Use a closure, create another function inside your function that contains this code like below. It'll execute on each iteration. Your problem is that Ajax is Asynchronous and will not execute before the loop finishes iterating resulting in only the last value from iteration coming back.

    function Closure(item, klass_id){
        klassification_ajax(item, function () {
            $('#all-klassifikation-' + item).collapse('show');
            $('#klassifikation-' + klass_id).css("font-weight", "Bold");
        });
    }
    

    Then to call it you would run the function.

    var j = 2;
    
    while (result['klass-' + j]) {
        klass_id = result['klass-' + j];
    
        if (handled_klass.indexOf(result['klass-' + (j - 1)]) == -1) {
            handled_klass.push(result['klass-' + (j - 1)]);
    
            Closure(result['klass-' + (j - 1)], 'klass-' + j);
        } else {
            $('#klassifikation-' + klass_id).css("font-weight", "Bold");
        }
        j++;
    }
    

    There are other ways you can implement it too, such as two different functions, one which runs the 'loop' more like a queue, one function which actually makes the request and in success callback runs the queue again.