How do I execute a function after the callbacks inside a for loop are completed?

前端 未结 2 516
独厮守ぢ
独厮守ぢ 2021-01-21 03:53

I have a for loop in a search function, with a function that does a callback that does a callback inside the loop, and I want to execute a BUILD() function after the loop, and a

相关标签:
2条回答
  • 2021-01-21 04:09

    I think you understand this already, but as it is the BUILD() is getting called linearly while the previous callback functions are still running. It's like you've created extra threads. One way to solve the problem would be to make BUILD a callback from the search function with the for loop in it. This would guarantee all functionality is complete before calling it.

    This question might help implement the callback: Create a custom callback in JavaScript

    0 讨论(0)
  • 2021-01-21 04:16

    With a small modification of your code, it can be achieved.

    var total = 1337; // Some number
    var internal_counter = 0;
    var fn_callback = function() {
        searchCallback.apply(this, arguments);
        if (++internal_counter === total) {
            BUILD();
        }
    };
    for (var i=0; i<total; i++) {
        service.search(request, fn_callback);
        ...
    

    Explanation

    First, we create a local function and variable.

    • The variable is a counter, which is increased when the callback is called.
    • The function is passed to the asynchronous method (service.search), which calls the original callback. After increasing the counter, check the value of the counter against the variable which holds the total number of iterations. If these are equal, call the finishing function (BUILD).

    A complex case: Dealing with nested callbacks.

    var types = { '...' : ' ... ' };
    
    function search() {
        var keys = Object.keys(types);
        var total = keys.length;
        // This counter keeps track of the number of completely finished callbacks
        //  (search_callback has run AND all of its details_callbacks has run)
        var internal_counter = 0;
    
        for (var i=0; i<total; i++) {
            var request = { '...' : ' ... ' };
            services.search(request, fn_searchCallback);
        }
    
        // LOCAL Function declaration (which references `internal_counter`)
        function fn_searchCallback(results, status) {
            // Create a local counter for the callbacks
            // I'm showing another way of using a counter: The opposite way
            // Instead of counting the # of finished callbacks, count the number
            //  of *pending* processes. When this counter reaches zero, we're done.
            var local_counter = results.length;
            for (var i=0; i<results.length; i++) {
                service.getDetails(request, fn_detailsCallback);
            }
            // Another LOCAL function (which references `local_counter`)
            function fn_detailsCallback(result, status) {
    
                // Run the function logic of detailsCallback (from the question)
                // " ... add place marker to maps and assign info window ... "
    
                // Reduce the counter of pending detailsCallback calls.
                //   If it's zero, all detailsCallbacks has run.
                if (--local_counter === 0) {
                    // Increase the "completely finished" counter
                    //  and check if we're finished.
                    if (++internal_counter === total) {
                        BUILD();
                    }
                }
            } // end of fn_detailsCallback
        } // end of fn_searchCallback
    }
    

    The function logic is explained in the comments. I prefixed the heading of this section with "Complex", because the function makes use of nested local functions and variables. A visual explanation:

    var types, BUILD;
    function search
        var keys, total, internal_counter, fn_searchCallback;
        function fn_searchCallback
            var result, status; // Declared in the formal arguments
            var local_counter, i, fn_detailsCallback;
            function fn_detailsCallback
                var result, status; // Declared in the formal arguments
    

    In the previous picture, each indention level means a new scope Explanaation on MDN.
    When a function is called, say, 42 times, then 42 new local scopes are created, which share the same parent scope. Within a scope, declared variables are not visible to the parent scope. Though variables in the parent scope can be read and updated by variables in the "child" scope, provided that you don't declare a variable with the same name. This feature is used in my answer's function.

    0 讨论(0)
提交回复
热议问题