WittCode💻

setTimeout of 0?

By

Learn about the JavaScript event loop, task queue, and Web APIs by understanding what setTimeout of 0 does. We will also go over how JavaScript is single threaded and asynchronous.

Table of Contents 📖

The Event Loop and the Call Stack

JavaScript consists of an event loop. A singly threaded loop where each iteration runs a chunk of code in the program. As the loop is single threaded, it cannot execute more than one task at a time. For the event loop to execute a task, it must be added to the call stack. Take the code below for instance.

function runSync() {
  console.log('runSync is on the call stack!');
}

function runSync2() {
  console.log('runSync2 is on the call stack!');
}

function runSync3() {
  console.log('runSync3 is on the call stack!');
}

runSync();
console.log('runSync is removed from the call stack!');
runSync2();
console.log('runSync2 is removed from the call stack!');
runSync3();
console.log('runSync3 is removed from the call stack!');

/**
 * Output:
 * runSync is on the call stack!
 * runSync is removed from the call stack!
 * runSync2 is on the call stack!
 * runSync2 is removed from the call stack!
 * runSync3 is on the call stack!
 * runSync3 is removed from the call stack! 
 */

Each of these functions is added and removed from the call stack synchronously, or one after the other. This is because JavaScript runs to completion. The current task is always finished before the next task begins.

setTimeout

However, JavaScript is also asynchronous. This means that certain code can be set to execute some time in the future. One way to execute something asynchronously in JavaScript is to use the setTimeout function.

function runSync() {
  console.log('runSync is on the call stack!');
}

function runSync2() {
  console.log('runSync2 is on the call stack!');
}

function runSync3() {
  console.log('runSync3 is on the call stack!');
}

function runAsync() {
  console.log('runAsync is on the call stack!');
}

setTimeout(runAsync, 0);
runSync();
console.log('runSync is removed from the call stack!');
runSync2();
console.log('runSync2 is removed from the call stack!');
runSync3();
console.log('runSync3 is removed from the call stack!');

/**
runSync is on the call stack!
runSync is removed from the call stack!
runSync2 is on the call stack!
runSync2 is removed from the call stack!
runSync3 is on the call stack!
runSync3 is removed from the call stack!
runAsync is on the call stack!
 */

In the code above, setting a timeout of 0 seems like the callback supplied should execute instantly, but this isn't true. This happens because of the event loop and concurrency. The JavaScript runtime can only execute one task at a time. However, the browser is more than just the JavaScript runtime. It also consists of Web APIs and queues.

JavaScript Queue and Web APIs

The browser Web APIs and queues allow JavaScript to do more than one task. The Web APIs are threads that we can make calls to. Calling setTimeout makes a call to the Web API which then handles the countdown for us. However, because the timer is 0 we would think that it would execute right away. This isn't true because JavaScript has priorities. The priority here is that the call stack has to be empty before the event loop can start executing callbacks from asynchronous tasks. When the Web API finishes with handling the setTimeout timer, it adds the completed callback to a task queue. When the call stack is empty, the event loop will start executing tasks from this task queue.

/**
 * |---------------|  ---------------> Web APIs --> Task Queue
 * |               |                                    |
 * |  call stack   |                                    |
 * |_______________|  <-- Event Loop   <----------------|
 */
setTimeout of 0?