Yibo Yang
Yibo Yang

Reputation: 2413

When exactly does the call stack become "empty"?

I've read several posts/SO threads on event loop, and according to MDN's article,

When the stack is empty, a message is taken out of the queue and processed.

As a JS novice, what I'm still confused about is -- when exactly does the call stack become "empty"? For example,

<script>
function f() {
  console.log("foo");
  setTimeout(g, 0);
  console.log("foo again");
}
function g() {
  console.log("bar");
}
function b() {
  console.log("bye");
}

f();
/*<---- Is the stack empty here? */
b();
</script>

The correct order of execution is foo - foo again - bye - bar.

But today I started thinking: isn't the stack technically empty right after exiting the f() call? I mean at that point we're not inside any function, and we haven't started any new execution, so shouldn't the setTimeout call message (which has been immediately queued) be processed, before moving on to b(), and giving the order of foo - foo again - bar - bye?

What if we have a million lines of code or some intensive computation to be executed and the setTimeout(func, 0) just sits in the queue for however long?

Upvotes: 21

Views: 3785

Answers (4)

RJM
RJM

Reputation: 1178

Although the block of code within the <script> tags isn't wrapped in an explicit function, it can be helpful to think of it as being a global function that the browser tells the javascript runtime to execute. So the call stack isn't empty until the code in the script block is done executing.

Upvotes: 11

Andrew Templeton
Andrew Templeton

Reputation: 1696

The simplest possible explanation: when all synchronous code in the current script, function, or event handler has finished running.

To directly answer "what if I have millions of lines..." Yes - your setTimeout call is stuck in the queue and will wait for its turn.

Upvotes: 3

jfriend00
jfriend00

Reputation: 707696

When the current piece of Javascript that is executing has finished and has no more sequential instructions to execute, then and only then will the JS engine pull the next item out of the event queue.

So, in your example:

f();
b();
// JS is done executing here so this is where the next item will be
// pulled from the event queue to execute it

Javascript is single-threaded which means the current thread of Javascript runs to completion, executing all instructions within a sequence until it hits the end of the code. Then, and only then, does it pull the next item from the event queue.

Here are some other answers that may help you understand:

How Javascript Timers Work

How does JavaScript handle AJAX responses in the background? (a whole bunch of Event Loop references in this post)

Do I need to be concerned with race conditions with asynchronous Javascript?

Can JS event handlers interrupt execution of another handler?

Upvotes: 5

Jacques
Jacques

Reputation: 3774

The best way I can think to explain it is that the call stack isn't empty until the code finishes running all relevant paths. A setTimeout of 0 simply pushes your code to the end of the stack.

When code runs at runtime, everything that will be run is part of the call stack, the order will be adjusted based on the order things are called and any timeouts/intervals/async methods that are called.

Some examples:

function foo() {
  console.log('foo');
}

function bar() {
  baz();
  console.log('bar');
}

function baz() {
  setTimeout(function() { console.log('timeout') }, 0);
  console.log('baz');
}

foo();
baz();
// call stack ends here, so, timeout is logged last.

// in console
// foo
// baz
// timeout

As you can see, bar is not included in the runtime stack because it is not called. If we have some HTML:

<div onclick="bar()">Bar runs</div>

When you click on that div, you will see baz, bar, then timeout logged to the console because the timeout is always pushed to the end of the currently running processes/call stack.

Hope this explanation helps!

Upvotes: 2

Related Questions