1

I'm writing a small app that does some processing to an input that takes longer than a couple seconds, so I wanted to wrap the processing in a Modal, such as

function exec()
{
    modal = document.getElementById("modal");
    modal.style.display = "block";

    // processing

    modal.style.display = "none";
}

Here is the JFiddle: https://jsfiddle.net/6mufcet3/4/

From what I've read, Javascript is a synchronous language, but through some debugging it looks like it jumps straight to the for loop without showing the modal.

Also, if I set breakpoints in my browser's dev tools, it seems to work perfectly fine. I'm not a web developer and therefore don't really know how Javascript is executed; if things are being rearranged, etc.

justynnuff
  • 461
  • 1
  • 6
  • 20

1 Answers1

2

You should use promises. The way you are implemented the exec function hide immediately the modal.

function execButton() {
  modal = document.getElementById("inModal")
  modal.style.display = "block"

  // Get some time to show the modal
  setTimeout(function() {
    const longTask = new Promise(function(resolve, reject) {
      let out = 0
      for (let i = 0; i <= 1000; i++) {
        out += i
        console.log(i)
      }

      resolve(out)
    })

    longTask.then(function(out) {
      modal.style.display = "none"
    })
  }, 100)
}

var button = document.getElementById("inButton")
button.onclick = execButton
.modal {
  display: none;
  position: fixed;
  z-index: 10000;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgba(0, 0, 0, 0.3);
}
<button id="inButton" type="button" class="button">Open</button>
<div id="inModal" class="modal">
  Modal
</div>

In the example I put the long task inside a setTimeout function, because the snippet needs some time to refresh the DOM.

  • At one point I tried promises, but couldn't get it to work. This solution worked perfectly. I have to wait 7 hours before I can give you the bounty. Can you explain in more detail why it wasn't working for me initially? Why does it immediately hide the modal instead of showing it? But when I run the code with breakpoints it works fine? Is there some part of my code that is asynchronous that I'm unaware of? – justynnuff Jul 23 '19 at 15:09
  • Ok. To understand what you did wrong, think about of your code in three parts: 1) modal-show part; 2) processing-part; 3) modal-hide part. Because of render cycle of dom (and how fast your processor is); you should execute (3) when (2) ends. The (2) part here can hang the rendering cycle of (1), so you could wait to show the dialog and then you could start the long task, or you could put the long task in a promise (any way, in some browsers you would need to delay the execution to allow the render cycle to show the dialog). – Mauro Stepanoski Jul 23 '19 at 15:41
  • You can read more about the render lifecycle here: https://stackoverflow.com/questions/44044956/how-does-browser-page-lifecycle-sequence-work – Mauro Stepanoski Jul 23 '19 at 15:41
  • 1
    So indeed I was right: the modal.style.display does not block until the CSS is rendered. It continues, and the processing task steps on the CSS rendering; which is why it works with debug breakpoints, but not in real time. – justynnuff Jul 23 '19 at 15:49
  • Yes. That's right. And debug breakpoints made the needed delays stopping in each step. – Mauro Stepanoski Jul 23 '19 at 16:15