简体   繁体   中英

Wait for all dom updates to complete

I have a page with several loading spinners that need to be displayed. I placed them in a function that I call when I need them (there is an opposite function for hiding them). I want my spinners to show up on the change event for a materializecss select box. The ID is on the select element. Immediately after those spinners appear there is a long running javascript process that follows. That consists of some api calls and long running loops. My problem is that I can't get the code to wait for all of the spinners to show up before running the javascript. I've tried setTimeout and requestAnimationFrame as several other posts suggest but the script starts anyway and the spinners are delayed in appearing.

HTML Snippet generated by materialize:

<div class="select-wrapper">
<input class="select-dropdown dropdown-trigger" type="text" readonly="true" data-target="select-options-262e9372-9f06-8033-4ddc-5ed565152b96">
<ul id="select-options-262e9372-9f06-8033-4ddc-5ed565152b96" class="dropdown-content select-dropdown" tabindex="0" style="">
<li class="disabled" id="select-options-262e9372-9f06-8033-4ddc-5ed565152b960" tabindex="0"><span>All Competitors</span></li>
<li id="select-options-262e9372-9f06-8033-4ddc-5ed565152b961" tabindex="0" class=""><span>Comp A</span></li>
<li id="select-options-262e9372-9f06-8033-4ddc-5ed565152b962" tabindex="0" class="selected"><span>Comp B</span></li>
<li id="select-options-262e9372-9f06-8033-4ddc-5ed565152b963" tabindex="0"><span>Comp C</span></li>
</ul>
<svg class="caret" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg>
<select id="competitor" tabindex="-1">
<option value="" disabled="">All Competitors</option>
<option value="a" selected="">Comp A</option>
<option value="b">Comp B</option>
<option value="c">Comp C</option>
</select>
</div>

Spinner Function:

function showLoadingSpinners() {
    $("#filtersSpinner").addClass("show");
    $("#mapSpinner").addClass("show");
    $("#tableSpinner").addClass("show");
    $("#submitButton").prop("disabled", true);
    if (listOfStuff.length >= maxStoresForPricing) {
        $("#tooManyMessage").fadeIn();
    }
}

Attempt A:

$("#competitor").on("change", function () {
    showLoadingSpinners();
    secondStep();

    function secondStep() {
        if (!$("#filtersSpinner").hasClass("show")) {
            window.requestAnimationFrame(secondStep);
        } else {
            doLotsOfStuff();
        }
    }
});

Attempt B:

$("#competitor").on("change", function () {
    showLoadingSpinners();
    setTimeout(function () {
       doLotsOfStuff();
    }, 350);
});

I would propose working with Javascript Promise on what you want to do and to be more exact it would be a really good idea to work with Promise.all() .

EDIT A small example for you to check is in the snippet below.

 const spinnerA = new Promise((resolve, reject) => { setTimeout(() =>{ document.getElementById("textA").style.display = "block"; resolve(true); },3000); }); const spinnerB = new Promise((resolve, reject) => { setTimeout(() =>{ document.getElementById("textB").style.display = "block"; resolve(true); },3000); }); Promise.all([spinnerA, spinnerB]).then(() => { alert(document.getElementById("last").textContent); });
 #textA { display: none; } #textB { display: none; } #last { display: none; }
 <div id="textA">text A</div> <div id="textB">text B</div> <div id="last">both text are in a visible state and you will see them once you close this alertbox </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM