skip to Main Content

I was playing around but I don’t understand why this won’t work? In theory, I thought it would but it just goes into an endless loop. Don’t run it, it will most likely lock up your computer.

glb = "original";

async function wait() {
    await new Promise(resolve => setTimeout(resolve, 2000));
    glb = "updated";
}

function f() {
    wait();
    var glb2 = "original";
    while (glb2 == "original") {
        glb2 = glb;
        console.log("####  glb:" + glb);
    }
    console.log("#### DONE  glb:" + glb);
}

f();

Why does glb2 never get updated?

Thanks!

3

Answers


  1. Well friend, this happens because the "await()" function returns a promise, which doesn’t give time to update the variable to "updated". For that, you need to make the function "f()" as asynchronous also waiting for the execution of the function "await()" with the use of the reserved word "await", as follows:

    async function f() {
        await wait();
        // rest of the function...
    }
    

    That way you can avoid the infinite loop.

    Good luck.

    Login or Signup to reply.
  2. JavaScript runtime is single-threaded and based on an event loop that runs to completion, meaning each item in the event loop’s queue needs to be completed before the next one can be processed.

    From MDN:

    Each message is processed completely before any other message is processed.

    This offers some nice properties when reasoning about your program, including the fact that whenever a function runs, it cannot be preempted and will run entirely before any other code runs (and can modify data the function manipulates). This differs from C, for instance, where if a function runs in a thread, it may be stopped at any point by the runtime system to run some other code in another thread.

    A downside of this model is that if a message takes too long to complete, the web application is unable to process user interactions like click or scroll. The browser mitigates this with the "a script is taking too long to run" dialog. A good practice to follow is to make message processing short and if possible cut down one message into several messages.

    This means that in your code, the while loop blocks the event loop, preventing any other operation queued (such as the promise resolution from the wait function) to be executed.

    This is also one of the reasons why setTimeout‘s delay is not guaranteed (they might actually take longer).

    This series of posts might be a better start to understand that than the MDN documentation IMO: ✨♻️ JavaScript Visualized: Event Loop

    Login or Signup to reply.
  3. If you want a loop that ends when a global variable is set to a certain value from outside of the loop, you must introduce an element of asynchronousness into the loop, so that the outside world gets a chance to modify the global variable. The following example uses a function that recursively invokes itself after 100ms. (You could also use a delay of 0ms, but a setTimeout or similar must be involved.)

    var a = "original";
    setTimeout(function() {
      a = "updated";
    }, 1000);
    
    function loop() {
      console.log(a);
      if (a === "original") setTimeout(loop, 100);
    }
    loop();

    Note that replacing the recursion with

    if (a === "original") Promise.resolve().then(loop);
    

    is not "asynchronous enough" to allow the setTimeout(..., 1000) to finish in between.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search