2

I have this function which waits for an asynchronous function to do its job and then returns.

function synchronous(){
    var notYet = true;

    setTimeout(function(){
        notYet = false;
    }, 1000);

    while(notYet)
        ;

    return "Done synchronously!";
}

console.log(synchronous());

Here the function synchronous stall using the while loop untill the callback of the asynchronous function (here setTimeout) get executed. But, the callback is never called (checked using an alert inside the callback), therefore, notYet will remain true and the function loop will go forever. So, why doesn't the callback get called after 1000 ms?

NOTE: I don't care how to make an asynchronous function into a synchronous one. My question is why the callback not getting called?

ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73

1 Answers1

6

The callback isn't getting called because the only thread that can call it is tied up doing your infinite loop.

In browsers, JavaScript runs on a single main UI thread (plus as many web workers as you want to create). That thread runs on a job queue: It picks up a job to do (for instance, processing a click), does the job, and then yields back to wait for the next job. You're blocking that one thread with the infinite loop. The timer schedules the callback in the job queue (probably, that's implementation-specific), but the thread never finishes the current job (the one that called your infinite loop) and so it never picks up that next job.

NodeJS also runs your code in a single thread and so does the same thing. (Not all environments do, but I'm not aware of any with setTimeout that don't schedule the timer callback on the same thread that requested it.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I tought of that. Then I replaced the `while` loop with a recursion function to give a chance for the callback to be executed. But didn't work. I'll post the code if you want to take a look. – ibrahim mahrir Jan 23 '17 at 19:31
  • 1
    @ibrahimmahrir: A recursive function doesn't yield back either, it just keep recursing. Think about it: If `foo` calls `bar`, you don't want a yield to happen in the middle (if you're writing single-threaded code, which is much simpler than writing multi-threaded code, hence this model being used in browsers). `foo` callling `foo` is no different. The only way to have it yield back is to have it "fall off" the end of the code. – T.J. Crowder Jan 23 '17 at 19:33
  • 1
    E.g., think of global code as though it were a function call. That function has to exit before the next job can be picked up. After that, every call you get will be a callback (event handler); the thread can't pick up the next job from the queue until that handler returns. – T.J. Crowder Jan 23 '17 at 19:39
  • Yeah, I understand now the **Javascript is a single-threaded language** did it for me. I thought that javascript was multi-threaded. I know the diference, I just didn't know that JS is the first type. Thanks. – ibrahim mahrir Jan 23 '17 at 19:45
  • 1
    @ibrahimmahrir: JavaScript **isn't** a single-threaded language. That's just how most (not all!) environments run it: One thread per global environment. – T.J. Crowder Jan 23 '17 at 19:47