setTimeOut + closures

setTimeOut + closures

by: Karishma Gajria Agarwal ( react.js dev with 1.5 years of experience )

SetTimeout + closures make one of the tricky topic to answer in the Js interviews. So by now you have undestood that this topic is really important , and should'nt be avoided according to interview perspective.

Prerequisites:

  1. Closures - A closure is a feature in js where inner function has access to the outer (enclosing) function variables - scope chain
  2. Scope Chain
  3. setTimeout

So let's get started with a simple que of setTimeOut + closures , then

function myFunc(){
    var i = 1;
    setTimeout(function(){
      console.log('i:',i);
    },1000);
    console.log('hey everyone!')
  }

  myFunc()

Guess the output!

I hope you have guessed it, now let me tell you the correct output:

image.png

explanation for this output

setTimeout(function(){
      console.log('i:',i);
    },1000);

This function forms a closure. So, this function remembers reference to i and it forms a closure. So, wherever this function goes it takes the refence of i along with it and here what does this setTimeout do `, it takes this callback and stores it into some place and attaches a timer to it and the Js proceeds and it does not wait for anything, it just goes to the next line and prints "hey everyone!" and that's how JS works and once the timer expires , it takes that function put it again to the callstack and runs it and that's how setTimeout works !

Now that was pretty simple, let's come to the tricky question that will blow up your mind!

what if I tell you to write a simple program that prints 1,2,3,4,5 after each and every second

This task is pretty simple ! so here goes my program

//second program
  function myFuncOne(){
      for(var i = 1; i<=5 ;i++){
        setTimeout(function(){
          console.log('value of i:',i );
        }, i*1000)
      }
    console.log('hey everyone! , program one is here!!');
  }
  myFuncOne()

So here goes the output

image.png

shocked to this see the output, I never expected this output !

explanation for this output : This result is due to closure

  1. What happens when a closure is formed ?? A closure is like a function along with its lexical environment. So even when function is taken out from its original scope, Still it remembers it's lexical environment. It can access to those variables of its lexical scope. So what will happen when the setTimeout takes this function and store it somewhere and attaches a timer so that function remembers the reference to i. So, here it remembers the reference to " i " , not the value of " i ". So when the loop runs the first time, so it like kind of makes a copy of this function and attaches a timer and also remembers the reference of iand similarly these 5 copy of these functions all of them are pointing to the same reference of i,because the environment for all of these functions are same. All of the copy of setTimeout callback function refer to that i. It refers to the same memory space This is the first important point to note here.

2.Second Imp point to note here is that - JS does not wait for anything.It will run the loop again and again and it will just quickly push that function, setTimeout will store all of these functions and js will move on. It will not wait for those timer to expire. So it will print "hey everyone! , program one is here!! ". and when the timer expires, it is too late and the value of i is 6, because the loop was constantly running it was 1,2,3,4,5, and finally 6. and when this callback function runs by that time the value of i is 6, in the memory location it is 6,so it will print 6 every time because all of these callback functions, all the copy all these functions(all of these 5 functions) are referring to the same spot same in the memory and that is same variable , which has now run 5 times and its value is 6.

So if try to retrospect that why it is behaving this way, then we get to know that it is because this i for each and every copy of the function is referring to the same spot in the memory that is i, this i which has now become 6because the loop was continuously running, by the time this callback gets a chance to execute, by that time the value of this i, has been changed because of this loop to 6.

Now how to fix this issue, as we are not getting the desired output ??

So, we can fix this using ' let '.

function myFuncTwo(){
    for(let i = 1;i<=5 ; i++){
      setTimeout(function(){
        console.log('i:', i);
      }, i*1000)
    }
    console.log('hey everyone! , program two is here!!')
  }

  myFuncTwo();

output :

image.png

now we can see the expected output. As we are using ' let ' over here instead of ' var ', we are getting the desired out as " let " has a BLOCK SCOPE, that means whenever every time this loop runs , this i is a new variable altogether and each time setTimeout is run this callback function has a new copy of i with it, with its own identity. As 'let' variables are block scoped , so each and every time loop is called , and everytime the setTimeout method is called this function forms a closure with a new variable itself that means the copy of i is new iterarion. So that means if we do i++ , here i=2 is a new copy of variable which forms a closure with this function. What will setTimeout do is , it will now take this function , now this function has a new copy of ibound to it , which has value 2 and send it and saves it , when i goes to 3, it forms a closure with i = 3, which is a fresh variable in itself and similarly keeps on doing it and makes 5 copies of this variable 5 and they form closure with each and every function. So In simple terms , you can assume that each and every time this function is called it is refferring to a different memory location , which is their individual i , separate copy of i, which was in the scope.

Why it was not working with var, while it was working with let ??? The only difference is that let is block scoped and it creates a new copy everytime this loop is executed.

Hope you enjoyed the read and can explain this concept in interview !