Why does the following JS function break the browser process?

var wait = function (milliseconds) {
    var returnCondition = false;
    window.setTimeout(function () { returnCondition = true; }, milliseconds);
    while (!returnCondition) {};
};

      

I know there have already been many posts on why not trying to implement a function wait()

or sleep()

in Javascript. So it's not about using it for implementation purposes, but rather for making it work for proof of concept.

Attempt

console.log("Starting...");wait(3000);console.log("...Done!");

      

freezes my browser. Why wait()

does it never seem to end?

Edit: Thanks for the answers so far, I didn't know that the while loop never lets you execute any other code.

So will this work?

var wait = function (milliseconds) {
    var returnCondition = false;
    var setMyTimeOut = true;
    while (!returnCondition) {
        if (setMyTimeOut) {
            window.setTimeout(function() { returnCondition = true; }, milliseconds);
            setMyTimeOut = false;
        }
    };
    return;
};

      

+3


source to share


2 answers


JavaScript runs in a single thread. Only when you exit the execution path is another execution path started. So the wait(3000)

following happens on startup :

  • returnCondition

    - false

  • timeout scheduled
  • an endless loop starts.

Each tag <script>

, each event handled, and each timeout (as well as updating the UI in the case of a browser) initiates a separate execution path. So a 3000 timeout is not guaranteed to start at 3000ms, but anytime after 3000ms when the motor is "free".

The function wait

never completes, so the script execution path never ends, and the scheduled timeout never comes.



EDIT:

This means that after the start of the tag <script>

or Node.js has started executing the JavaScript file, the execution must hit bottom before anything else can happen. If a function is triggered by an event or timeout, that function must exit before anything else can happen.

<script>
  console.log("script top");
  function theTimeout() {
    console.log("timeout top");
    // something long
    console.log("timeout bottom");
  }
  setTimeout(theTimeout, 0);
  setTimeout(theTimeout, 0);
  console.log("script bottom");
</script>

      

There are three ways to do it. The first is a tag <script>

: it starts by printing "script top", assigns two timeouts (for "right now"), then it prints "script bottom" and then ends up <script>

and the interpreter doesn't work. This means that it has time to complete another path of execution, and there are two wait timeouts, so it picks one of them and starts executing it. While it is running, it cannot do anything again (not even UI updates); another timeout, although it was also scheduled to be "immediately", remains to wait until the first completion timeout has elapsed. When this happens, a second timeout will occur and it will be executed as well.

+5


source


JavaScript is single threaded. When you call the setTimeout method, the method you passed as an argument is pushed onto the async call stack. This means that the next line of code in your block is executed immediately after the call to setTimeout, and the function you passed as an argument will be executed after the wait method finishes.

Your while loop is waiting for a state that will never happen when the wait function is running, because the function that will set your flag won't run until the wait function is executed.

The correct way to wait is waiting:

var wait = function (milliseconds, onEnd) {

    window.setTimeout(function () { onEnd(); }, milliseconds);

};

wait(1000, function(){alert('hi')});

      

Here you are passing a callback function that will be executed after the timeout.

If you have multiple calls like asynchronous call, you can use promises. Promises will make your code easy to read and it will be easy to combine multiple asynchronous calls. There are some very good promising librarians: JQuery has $ .Deferred built into it, but you can use Q if you are writing node.js code.



The implementation of the promise style would look something like this:

var wait = function (milliseconds) {

    var onEnd = null;

    window.setTimeout(function () { onEnd(); }, milliseconds);

    return {

    then: function(action){
            onEnd = action;
    }

    }
};

wait(1000).then(function(){alert('hi')});

      

https://api.jquery.com/jquery.deferred/ https://github.com/kriskowal/q

The following book helped me a lot to understand this topic:

Async JavaScript: Build More Responsive Apps with Less Trevor Burnham's Code https://pragprog.com/book/tbajs/async-javascript

+2


source







All Articles