• TheCPUWizard (unregistered)

    First call to Initializes invokes the "else"...all future calls invoke the "then"... Not threading related at all, but a means of ensuring executred only once (and only safre in a single threaded environment)

  • Hanzito (unregistered)

    It may be an attempt at preventing to call an API before the previous call finished. But perhaps "lock" is short for "deadlock".

  • (nodebb)

    I mean, someone wrote JS by hand instead of using web assembly and that's pretty much the quality and lack of understanding you expect, so...

  • trainbrain27 (unregistered)

    Race conditions are foggy, therefore a crash is likely. Red flag!

  • (nodebb) in reply to TheCPUWizard

    Yes, if the flag was named initializeHasAlreadyBeenCalled or some semantic equivalent, we would not give this code a second thought.

  • Stefan (unregistered)

    You'll be shocked to learn that the lock is "released" in an entirely different function, making it even more wrong.

    Could it be that the author has misunderstood what "lock" actually is intended to do?

  • WTFGuy (unregistered)

    Except for the part where Remy tells us the "lock" is reset to false elsewhere in the code.

    The one thing we can be pretty sure of is that this is NOT some sort of execute-once-only flag.

  • (nodebb)

    I think the other function is a callback for some async function. JavaScript is "multithreaded" in the sense that there are functions that you'll call with one of the parameters being a call-back function (at least before async/await were a thing), and it would return long before it would complete its task so that you won't lock up the main thread. The lock here mostly is a way to prevent multiple request to an async function.

  • (nodebb)

    I could see this sort of guard against reentrant calling being useful. When you process more events inside an event handler, you need to be really quite careful.

    Addendum 2023-09-07 10:47: Note that this is true even when single-threaded. A long time ago I got an application into a terrible tangle because of not being careful about this.

  • (nodebb)

    @dkf While avoiding reentrant execution of events is important this code will not accomplish that reliably. So long as you don't have much code between the test and the set the odds of being hit are low, not zero. My approach is to assume Moriarty can see what your code is doing and decide when to act to mess you up. Otherwise you won't be paranoid enough about low probability failure scenarios.

    The only case this works is where it's an issue of possible recursion rather than concurrency. I have implemented many locks like this against recursion threats.

  • mihi (unregistered) in reply to LorenPechtel

    In a Javascript environment in the browser, reentrance is effectively recursion, when you look at the call stack. Events are either added to the end of the event queue (when no reentrance can happen) or executed immediately upon DOM manipulation (which results in an event handler "calling itself" when you look at the call stack.

    So for example:

    function someOnChangeEvent(e) { if (!inProgressOfChange) return; inProgressOfChange = true; DoSomethingWithTheElementThatFiredTheEventWhichMayFireTheEventAgain(); inProgressOfChange=false; }

    is a valid pattern to work around reentrance issues in JavaScript in the browser.

  • (nodebb)

    I use this sort of set up all the time when dealing with asynchronous operations involving XMLHttpRequest / Fetch.

    Nothing worse than clicking a button, and even though it might throw a message up on the screen, the user dismisses the message and keeps clicking the button repeatedly.

    So, on things that I know could take a little bit of time to perform their magic, when I call the function, I check to see if a variable has been assigned the value of 'true', if it has, I bail out.

    If it hasn't, then I set the variable to true and continue on and perform the fetch-request.

    Once the fetch-request comes back (or fails), I set the variable to false again.

    This ensures the fetch-request can only run once.

    Javascript might be single-threaded, but since it supports asynchronous functionality, one must account for that too.

  • Nick (unregistered)

    I love how wrong so many of the comments can be. In particular, everyone clutching their pearls at the terrible mistake of having several lines of code between the check and then setting the lock flag to true…

    Remind me, please… if JavaScript is single-threaded, how can any code get executed on some other thread while this function is still executing?

  • (nodebb)

    Very interesting comments. So what may look like a very questionable design pattern may be a very commonly justifiable pattern to avoid executing an async twice (been there, done that *).

    There's still one WTF though. What I take from this is that we would not be here if there had been one short explanation comment on the "lock" variable, and more importantly naming it appropriately as "operationPending" or some such.

    (* I'm a previous lifetime in win32, I'd do something similar by disabling a submit button while waiting for server reply or error; the button state thus provided that "lock" but with much clearer semantics).

  • LZ79LRU (unregistered) in reply to Ralf

    Honestly I prefer the name lock in this instance because it clearly tells us of the intention behind it. After all, anyone reading the code is likely to know what a lock is and immediately conclude what the intent was. Where as something like operationPending is far more ambiguous. It could for example be a flag that handles several different operations and indicates that "a" operation is pending rather than the operation. Etc.

  • (nodebb)

    Some toy example where a "lock" logic would make sense, though probably be a bad way to implement it:

    <html>
      <body>
        <div style="width: 100; margin: auto; border: solid black 1px; background: black">
          <span id="circle" style="border: solid black 1px; background: white"/>
        </div>
        <script>
          const circle = document.getElementById("circle");
          
          let lock = false;
    
          let counter = 0;
          setInterval(function incrementCounter() {
              if(! lock) {
                  counter++;
                  circle.innerText = counter;
              }
          }, 25);
    
          let position = 0;
          setInterval(function moveCircle() {
              position += 1;
              if(position > 100) {
                  position = 0;
              }
              circle.style.marginLeft = position;
              if(position < 50) {
                  lock = false;
              } else {
                  lock = true;
              }
          }, 25);
    
        </script>
      </body>
    </html>
    

    Addendum 2023-09-11 04:52: Mostly, lock is an awful variable name here.

    Addendum 2023-09-11 04:53: In my defense, before I switched to the current style of the toy example, the moving element was a circle.

  • (nodebb) in reply to Nick

    The main thread is single-threaded, but Javascript has support for background threads.

    So anything on the main thread will be dealt with top-down, when it hits an async task, it spins it off into a background thread with a callback, once the async task has finished, the callback (or promise) is called with whatever it needs to be passed.

    Course, if it is something like an event listener, where you might click on a button and perform an async task, you kinda need to ensure the button can't be pressed repeatedly, thus spawning off multiple background threads.

    So the usual method is to set a flag, check the flag when the button is pressed, if false, set flag to true then run async task, if true, then bail out.

Leave a comment on “Threading in JavaScript”

Log In or post as a guest

Replying to comment #:

« Return to Article