setTimeout
What is setTimeout ?
setTimeout() is a JavaScript Function which is utilised to induce a delay in performing a task (Or a set of instructions). setTimeout does not block subsequent instructions until the statements within it are executed. Subsequent instructions gets executed in the order in which they appear on call stack. It's an Asynchronous Operation (Non-blocking in nature).
Non-Blocking Nature
As the Call Stack encounters a setTimeout(), it pushes the instructions specified within the setTimeout() to an Event loop and proceeds to execute instructions following the setTimeout() block (in the call stack). One the timeout duration elapses, the Callback Queue picks the instructions in the setTimeout puts them back on to the Call stack.
Syntax
setTimeout( // non-blocking
function() {
/* Execute this block after some MilliSeconds */
} /*, duration_in_miliseconds */
);
Input Parameters
- setTimeout accepts a callback function with a set of instructions
- Number of MilliSeconds that it needs to execute the instructions inside the function
Return
- Returns an Interval ID to uniquely identify the block that will be executed in a while
Note that I have used IIFE and ES6 syntax( ==> ) to present my Illustrations
click me for more information on IIFE
click me for more information on ES6 ==>
intervalId
Illustration - 1
(function() {
var intervalId = setTimeout(() => { // non-blocking
console.log(intervalId); // blocking within setTimeout
console.log("Illustration - 1"); // blocking within setTimeout
}, 4000); // executes above instructions after 4 seconds
})();
Take-Aways
setTimeout() is utilised to execute the following statements after 1000 mili seconds / 1 second
console.log(intervalId);
console.log("Illustration - 1");
Also an Identifier intervalID can be assigned as a return variable to Uniquely identify the setTimeout()
Illustration - 2
console.log("2.1 Hello"); // blocking
(function() {
setTimeout(() => { // non blocking
console.log("2.3 Illustration - 2"); // executes immediately
});
})();
console.log("2.2 Hello"); // blocking
Take-Aways
- We need not pass the milliseconds parameter in which case the block of code within setTimeout behaves like regular blocking instructions and will get executed without a wait.
- But since setTimeout is non-blocking in nature the subsequent blocking instructions post setTimeout() will still get precedence as shown above
clearInterval
If the wait is too long, and one wants to terminate the timeout, clearTimeout(intervalId) will stop/halt instructions in the block from getting executed
Illustration - 3
(function() {
var intervalId = setTimeout(() => { // non-blocking
console.log("Illustration - 3"); // will not get executed !!!
}, 5000);
clearTimeout(intervalId); // clears intervalId immediately
})();
Take-Aways
- Note that in the above illustration, clearTimeout() will immediately execute; as its blocking in nature
Scope
Illustration - 4
(function() {
var glob = "I am everywhere"; // blocking
console.log("4.1 : ", glob); // blocking
setTimeout(() => { // non-blocking
console.log("4.3 : ", glob); // blocking within setTimeout
}, 2000);
console.log("4.2 : ", glob); // blocking
})();
Take-Aways
- Since setTimeout is nonblocking instruction to the interpreter, its pushed to Event Loop and the next instruction in the call stack (which logs 4.2..) will be logged
- Once the wait is over, which is 2 seconds, instruction within setTimeout block will be picked from callback queue and gets executed
Illustration - 5
(function() {
for (var i = 0; i <= 2; i++) { // blocking
setTimeout(() => { // non-blocking
console.log("5.2 : ", i); // blocking within setTimeout, 5.2 :3
}, 2000);
}
console.log("5.1 : ", i); // blocking, 5.1 :3
})();
Take-Aways
- In this Illustration, for-loop statements and console.log('5.2..') are blocking statements and hence will get executed first.
var i = 0; i <= 2; i++;
console.log("5.2 : ", i);
- For each iteration, the setTimeout instruction
console.log("5.2 : ", i);
will be pushed to the Event Loop and loop counter "i" in the Call Stack keeps incrementing until it reaches 3 - Post which, the next subsequent blocking instruction will be picked (i.e
console.log("5.1 : ", i);
). At this point, variable "i" holds a value of 3 in it and hence gets printed5.1 :3
. - Post the timeout duration, setTimeout instruction (non-blocking)
console.log("5.2 : ", i);
gets picked and finds that the current value of i in the Call Stack is 3 and logs the same on to the console
Illustration - 6
(function() {
let i = 0; // blocking
while (i <= 3) { // blocking
setTimeout(() => { // non-blocking
console.log("6.2 : ", i); // blocking within setTimeout (prints 6.2 :4 (thrice))
}, 2000);
i++; // blocking
}
console.log("6.1 : ", i); // blocking (prints 6.1 :4)
})();
Take-Aways
- Scoping is similar to var
- Picks the latest value from call stack
Illustration - 7
(function() {
let wc = "hello"; // 1: blocking
let name = ""; // blocking
setTimeout(() => { // non-blocking
name = "Sharu"; // blocking within setTimeout
console.log("7.2 : " + wc + " " +name); // blocking within setTimeout (7.2: hello Sharu)
}, 2000);
console.log("7.1 : ", wc + name); // 3: blocking, (7.1 hello)
})();
Take-Aways
- Post setTimeout(), subsequent instructions does not wait for setTimeout() instructions(callback) to complete. 2. The Call Stack picks instructions specified after setTimeout() and executes them; as, the instructions within setTimeout() wait for the specified duration in the Event Loop
- In order to execute instructions after the specified duration, one should write them within the setTimeout() block only
- Instructions within the setTimeout() will execute instructions - within them - in a blocking way
Callback hell
Illustration - 8
(function() {
alert("8.1 Welcome to XYZ"); // 1. Blocking
setTimeout(() => { // Non Blocking
var name = prompt("8.2 Please enter your Name : "); // 2. Blocking within setTimeout
setTimeout(() => { // Non Blocking
alert("8.3 Welcome " + name); // 2. Non Blocking
}, 1000); // 1 second
}, 1000); // 1 second
})();
Take-Aways
- A chain of callbacks with setTimeout can be achieved as shown above, as the inner setTimeout gets blocked by its parent. Once the parent setTimeout completes, the inner setTimeout is pushed to Event Loop
- But invoking them repeatedly in this fashion makes it very difficult to read, debug them and hence becomes difficult to manage in the long run
- This is called commonly termed as "Callback hell"
- There are mechanisms to avoid this using Async() and Await()
There are indeed limits for setTimeout function Illustrated as shown below. setTimeout accepts a Signed Integer in milliseconds
Range [ 1 - 2^31 ]
(function() {
setTimeout(() => {
console.log("Hello !!!");
}, 0);
setTimeout(() => {
console.log("I am ~ [24.85 Days -1 Millisecond] away");
}, Math.floor(2 ** 31 - 1));
setTimeout(() => {
console.log("I am ~ [24.85 Days] away");
}, Math.floor(2 ** 31));
setTimeout(() => {
console.log("I am ~ [24.85 Days + 1 Millisecond] away");
}, Math.floor(2 ** 31 + 1));
setTimeout(() => {
console.log("I am [1 Millisecond] away");
}, 1);
setTimeout(() => {
console.log("GoodBye !!!");
}, 0);
// Output:
// Hello !!!
// I am ~ [24.85 Days] away
// I am ~ [24.85 Days + 1 Millisecond] away
// I am [1 Millisecond] away
// GoodBye !!!
})();
Take-Aways:
- Anything on-or-above 2^31 is defaulted to 1 Millisecond and hence the behaviour
- Anything between 1 Millisecond and 2^31 (not inclusive) will go into a callback and wait for their set duration to resume execution
- As shown above, as 1 millisecond is such a short duration that its almost equivalent to 0 Milliseconds and hence the callback instructions within that setTimeout gets printed even before setTimeout() with 0 Milliseconds (GoodBye !!!) is consoled !!
- Note that this behaviour changes with browser-to-browser and one should test and verify in multiple browsers