Search code examples
javascriptfunctionreturn

How can I ensure an if loop waits for and receives a result before running the next if loop in sequence


I have a javascript function where if loops are not following each other sequentially. I need them to run one after the other. The second loop should not run until the first loop has finished, because it deals with the output of the first.

  1. I use an if loop (loop 1) to call a function in a child iframe (this frame contains mapping elements, and I can't reasonably combine it with the parent frame). This part is working as intended.

  2. The function in the iframe is triggered, and it makes a call to an external service, and awaits a response. When it receives a response it passes either "error" or "ok" back to the parent function by using the 'return' function. This part is working as intended.

  3. The parent receives the response, sets a variable and then should continue on with the next if statement (loop 2) that does something else.

What actually happens is that loop 1 runs, then loop 2 also runs, and loop 2 returns results before loop 1 - which screws things up as loop 2 is meant to be dealing with thee results from loop 1.

jQuery(document).on('click', '.gv-button-delete', function (e) {
        e.preventDefault();  //prevent submission
        console.log('Intercepted delete button request');
        var delLoc = "";
        (function ($) {
            var delLoc2 = $('.gv-button-delete').attr("href"); //capture default action, because we need the time-valid nonce
            delLoc = delLoc2;
        }(jQuery));

        var objID = document.getElementById("input_4_40").value;
        objID = parseInt(objID);
        var iframe = document.getElementById("MapFrame1");
        var result = "";
        if (iframe) { //1st if loop that collects the answer
            var iframeContent = (iframe.contentWindow || iframe.contentDocument);
            var result = iframeContent.WriteLog(objID); //call the function from the iframe, and hopefully wait for a result. 
            console.log(result);
        }
        if (result == "error") { //the second if loop
            console.log("Step 5")
            console.log("There was an error with removing the feature");
        } else if (result == "ok") {
            console.log("Step 5")
            console.log("The spatial delete completed correctly");
        } else {
            console.log("Step 5")
            console.log("unexpected result of spatial delete")
        }

    });

the iframe code, becuase it's useful for context.

function WriteLog(objID){
        var retireFeatureID = hotspots.getFeature(objID);
        var successStatus = "";
        retireFeatureID.feature.properties["SystemStatus"] = "Deleted";
        hotspots.updateFeature(retireFeatureID.feature, function (err, response) { //This is a syncronous call to another service
            if (err) {
                console.log("Step 3")
                console.log(err);
                successStatus = "error";
                console.log("successStatus is: " + successStatus);
            } else {
                console.log("Step 3")
                console.log(response);
                successStatus = "ok";
                console.log("successStatus is: " + successStatus);
            }

        });
        console.log("Step 4")
        console.log("Updated the status of feature: " + objID);
        console.log("child iframe has variable successStatus as: " + successStatus);
        return successStatus;
    }

What actually happens is that the console results look like:

Step 4

Step 5

Step 3

The second loop is returning before the first loop has finished and returned a result.


Solution

  • This might be due to how callbacks and the javascript event loop work in general, and steps 4 and 5 will be executed first before step 3.

    The function response callback will be placed at the end of call stack, which causes the remaining code (step 4 onwards and second if loop) to be executed without waiting for the callback to complete despite the other service code being synchronous.

    I would suggest you to either convert the service function to one with a direct return and if possible not using callbacks, or changing the WriteLog function to a callback function by adding a callback argument and invoking it once you get the response from the other service.

    JavaScript Event Loop Explained