Engineer bro!
Mon Feb 21 2022 (2 years ago)
Engineer by mistake!
I am a software engineer by passion
This is a very hot question in the JavaScript world. It has been asked so many times in the JavaScript interview. In this article, I'll try to explain to you the concept behind this.
This question requires that you should have basic understanding of JavaScript, execution context, closures, setTimeout, setInterval and recursion. Although, I'll try to cover a few of them in the article itself.
setTimeout()
?setTimeout() is an API provided by a JavaScript execution environment. It is used to execute a specific set of code after some time.
setTimeout(()=>{
console.log("Log me after 2 seconds :)")
},2000)
The above function will print Log me after 2 seconds :)
after 2 seconds. It might not print it after exactly 2 seconds, because your thread can be busy at that time.
setInterval()
?setInterval() is an API provided by JavaScript execution environment, which is used to execute the specific set of code at some time interval.
setInterval(()=>{
console.log("Log me after every 1 seconds...");
},1000);
In computer science, recursion is a method of solving a computational problem where the solution depends on solutions to smaller instances of the same problem.
In simple terms, when a function call itself, then it is called recursion.
function recur(){
console.log("Recursion ... ");
recur();
}
recur();
/*
O/P
Recursion ...
Recursion ...
Recursion ...
...
*/
setInterval()
Before creating setInterval
, let's note down the parameters and return value.
setInterval()
func - a function is passed, that will be executed at a specific time interval.
delay - the amount of interval in milliseconds, default is 0.
args - arguments that will be passed to the callback function.
setInterval()
intervalID
- It is a numeric, non-zero value which identifies the timer created by the call to setInterval()
. This value can be passed to clearInterval() to cancel the interval.
customInterval()
// cb - callback function
// delay - the amount of interval
function customInterval(cb,delay){
// logic goes here...
}
Now, i have defined the customInterval()
, so first we would have to execute the provided callback function at the given time interval.
// cb - callback function
// delay - the amount of interval
function customInterval(cb, delay) {
setTimeout(() => {
cb();
// use recursion to call the call back again
customInterval(cb, delay);
}, delay);
}
customInterval(
() => console.log("Interval-", new Date().toLocaleTimeString()),
1000
);
// output
Interval- 12:26:14 pm
Interval- 12:26:15 pm
Interval- 12:26:16 pm
...
Now, the function is being called at the given time interval, but how can we clear the interval. To clear the customInterval
we need the timer id returned by setTimeout
.
But, the hack is here is that we need the latest timer id returned by setTImeout
.
As i have mentioned that, we need the id returned by setTimeout
for clearing the interval. But, we are calling the above function in recursion. A function can return a value only one time, so how do we get the id of the latest setTImeout
out of the function customInterval
.
Let's have a look at the below function.
function test() {
let value = 0;
value++;
console.log("Value inside test - ", value);
setTimeout(test, 1000);
return value;
}
let value = test();
setInterval(() => {
console.log("Value outside test - ", value);
}, 1000);
The above code is just for testing
When you execute the above code, you will get the below output.
Value inside test - 1
Value inside test - 1
Value outside test - 1
Value inside test - 1
Value outside test - 1
....
There is two questions is arising from the above output
Why value inside the function is not updating- because we are setting in each function call.
Why value outside the function is not updating - because a function can return a value only once.
So, the question is that how can we get updated value outside the function?
The answer is by creating a closure.
Have a look at the below code.
function test() {
let item = {
value: 0,
};
// this function will create a closure
function inc() {
item.value++;
console.log("Value inside test ", item.value);
setTimeout(inc, 1000);
}
inc();
return item;
}
let item = test();
setInterval(() => {
console.log("Value outside test - ", item.value);
}, 1000);
When you execute the above code, you will get the below output.
Value inside test 1
Value inside test 2
Value outside test - 2
Value inside test 3
Value outside test - 3
Value inside test 4
Value outside test - 4
Value inside test 5
As you can see in the above function, we are getting the updated value outside the function, this is just because of closure created by inc()
function.
Here the closure is created by inc()
function which will remain till inc()
will executed. And we are calling the inc()
function recursively, so it'll be there always.
As you have seen in the previous section, we are able to get the updated value outside the function at some time interval. So, we can use the above concept to get the id of the latest setTimeout
outside the customInterval
to clear the timer. Once the timer is cleared using clearTimeout
, it'll automatically stop.
function customInterval(fn, delay) {
const interval = {
id: null,
};
function timeOut() {
interval.id = setTimeout(() => {
fn();
timeOut();
}, delay);
}
timeOut();
return interval;
}
const timer = customInterval(() => {
console.log("In Side Custom Interval");
}, 1000);
setTimeout(() => {
console.log("Called clear interval");
clearTimeout(timer.id);
}, 5000);
When you execute the above function, you'll get the below O/P.
In Side Custom Interval
In Side Custom Interval
In Side Custom Interval
In Side Custom Interval
Called clear interval
As you can see in the above function, an object interval
is returned by the customInterval
. We are storing the reference of interval
inside timer
variable outside the function.
So, whenever timeOut
will update interval.id
, we can get it's updated value in timer.id
function.
As you can see we have used clearTimeout(timer.id);
. This basically clears the timer.
© 2021 dsabyte. All rights reserved