2

I have the following JavaScript. The attached code is extremely simplified version of rather complex auto-generated JavaScript that launches the same function on lots of objects (not in loop, but just a bunch of function calls generated).

The problem is that the code is supposed to update an element on each launch of the function. However, that does not happen. Instead, when I press the button it freezes and updates status only after all functions are performed (to "Done"). So why the element is not updated on each call of long_function() in the following code (and how do I fix that):

<html>
    <body>
        <h1 id="status">Not yet started</h1>
        <button onclick="perform()"> Start! </button>

        <script type="text/javascript">
            function sleepFor( sleepDuration ){
                var now = new Date().getTime();
                while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
            }

            function long_function(number)
            {
                document.getElementById("status").innerHTML = number;
                sleepFor(1000);
            }

            function perform(number) {
                long_function(1);
                long_function(2);

                document.getElementById("status").innerHTML = "Done";
            }
        </script>
    </body>
</html>

(The problem happens in Google Chrome and Safari)

(Sleep function is taken from answer to What is the JavaScript version of sleep()?)

Community
  • 1
  • 1
Dmitry Torba
  • 3,004
  • 1
  • 14
  • 24

1 Answers1

3

This is how I understand what happens:

  1. Function perform() runs, and it calls long_function(1) first.
  2. The innerHTML call gets sent.
  3. The sleepFor(1000) function gets called, but the browser hasn't rendered the innerHTML change yet.
  4. The live compiler runs through the while loop in sleepFor(), which is blocking by nature (it stops other JavaScript code from running but it also stops the browser from rendering).
  5. Once the while loop is done, JavaScript proceeds to set the innerHTML of your element to "Done", but it never got to render the number in long_function().

If you want an interesting watch on the event loop, blocking and non-blocking JavaScript, here are some resources:

http://latentflip.com/loupe/

This question is a bit misleading because of the title (innerHTML doesn't actually run asynchronously) but the answers are interesting:

innerHTML can't be trusted: Does not always execute synchronously

Community
  • 1
  • 1
fnune
  • 5,256
  • 1
  • 21
  • 35