0

I have this function which takes a few seconds to complete, and I need to wait for it to complete before anything else can happen in my application. I tried implementing an async function which returns a promise but still, the function load_structure is being executed before any other functions in the load_question(). I need them to execute in the order they appear (or at least, the load_structure needs to be called before the two succeeding functions can be executed).

My code looks like this

function show_loading() { // All of the show/hide functions work on this principle
    document.getElementById('loading').removeAttribute("hidden");
}

async function generate_html_a(){  // Same for B and C just different logic
   // Spends a few seconds rendering some HTML objects
}

async function load_structure(){

     if(a){
         await generate_html_a(); // renders a bunch of images which takes a few seconds
     }else if(b){
         await generate_html_b();
     }else if(c){
         await generate_html_c();
     }
}

async function load_question(){
     hide_question();
     show_loading();
     await load_structure();
     hide_loading();
     show_question();    
}

Edit: I think I have boiled it down to a reprex.

function show_loading() {
  document.getElementById('loading').removeAttribute("hidden");
}
function hide_loading() {
  document.getElementById('loading').setAttribute("hidden", "");
}

async function load_html_a() {
  document.getElementById("question").innerHTML = '';

  for (i = 0; i < 100000; i++) {
    var container = document.createElement('div');
    container.innerHTML = 'aaaaaaa';
    //container.setAttribute("hidden", "");
    document.getElementById("question").appendChild(container);
  }
  //document.getElementById("question").innerHTML = '';

  return;
}

async function load_structure() {
  if (1 == 1) {
    await load_html_a();
  }
  return;
}

async function load_question() {
  console.log("start");
  show_loading();
  await load_structure();
  hide_loading();
  console.log("done");
}
<div id='loading' hidden>loading</div>
<button onClick='load_question()'>Load</button>
<div id='question'></div>
pilchard
  • 12,414
  • 5
  • 11
  • 23
Daniel C
  • 31
  • 6
  • sync functions will always run before async if called in same block, you can use things like `await` or `promise chaining` to change this behavior. – Ace Oct 21 '22 at 15:13
  • @YAN But in this case, the async function load_structure is being run before my other functions... – Daniel C Oct 21 '22 at 15:14
  • 1
    All `async` functions return a promise, no need to wrap it in another. For more concrete help you'll need to post more code as there is no reason for you assertion based on what you've shown. – pilchard Oct 21 '22 at 15:15
  • @pilchard I have tried them as both async and normal functions with no change in the outcome – Daniel C Oct 21 '22 at 15:21
  • Your problem is probably in the missing code - `generate_html_a`, etc ... you probably haven't linked the returned promises to `onload` or other relevant events. – kikon Oct 21 '22 at 15:24
  • OK working on a reprex. Thank you all for the comments. – Daniel C Oct 21 '22 at 15:25
  • @pilchard Added reprex – Daniel C Oct 21 '22 at 15:47
  • @pilchard The issue is that the function call for "loading" isn't being called before load_question(). Also thanks for reformatting. I'm still learning here – Daniel C Oct 21 '22 at 15:53
  • You don't `await` anything in `load_html_a` and don't return a Promise, so why is it marked `async`? You've written a synchronous function. The consequences are that `load_structure` is also synchronous, and therefore `load_question` is also synchronous. – Wyck Oct 21 '22 at 15:57
  • see: [Is async await truly non-blocking in the browser?](https://stackoverflow.com/questions/42773714/is-async-await-truly-non-blocking-in-the-browser) – pilchard Oct 21 '22 at 15:57
  • The functions are being called in the right order, but the DOM is blocked until the call is complete, at which point you've already hidden the loading again. See the duplicate above. – pilchard Oct 21 '22 at 15:59
  • As far as I can tell, you're hoping that your `for (i = 0; i < 100000; i++) {` loop of creating a bunch of DOM elements can somehow be done asynchronously, is that right? Presumably because it takes a long time to add a hundred thousand divs to your document? Not sure what you hope to accomplish in the meantime; DOM manipulation is synchronous. I suppose you could space out the updates into batches with timer ticks. – Wyck Oct 21 '22 at 16:06
  • What's actually going on here is the rendering of about 2MB of base64 images. The purpose of that example was to show that rendering of lots of elements in the DOM was what is slowing our program down to the point where we gotta show a loaing icon. – Daniel C Oct 21 '22 at 16:08

1 Answers1

0

Solved by restructuring like so

function show_loading() { // All of the show/hide functions work on this principle
    document.getElementById('loading').removeAttribute("hidden");
}

async function generate_html_a(){  // Same for B and C just different logic
   // Spends a few seconds rendering some HTML objects
}

async function load_structure(){

     if(a){
         await generate_html_a(); // renders a bunch of images which takes a few seconds
     }else if(b){
         await generate_html_b();
     }else if(c){
         await generate_html_c();
     }
     hide_loading();
     show_question();  
}

async function load_question(){
     hide_question();
     show_loading();
     setTimeout(load_structure, 50);
  
}



Daniel C
  • 31
  • 6
  • I don't see how this is different apart from delaying the load by 50 milliseconds. What did this accomplish for you? – Wyck Oct 21 '22 at 16:07
  • Because the DOM doesn't render until the function is complete, the load_question function is actually being called in order - but the changes aren't rendered until the function has completed. So we set a timeout on the load_structure so the DOM has a chance to update with the loading icon before it takes on the load. – Daniel C Oct 21 '22 at 16:10