I am trying to create a timer with while loops and setTimeout but everytime i give an input the code crashes. İ thought doing it this way would work but seems like it doesnt. What is the problem here? And how do i achieve what i want with while loop and setTimeout?
function countdown(durationInput) {
while (durationInput > 0) {
setTimeout(() => {
console.log(durationInput)
durationInput = durationInput - 1
console.log(durationInput)
}, 1000)
}
}
Well look at this image. What you see is the basics of how javascript works.
JS is single threaded. That means 1 core do the work. Thats the event loop.
The event loop grabs the event from the callback queue and put its on the call stack and executes it.
If you run setTimeout you put it into the callback que
The problem: When the event loop is blocked by an synchronouse task like your while loop, that means the event loop cannot grab the events to the stack, because its blocked.
What happens is: The while loop runs and runs and adds more and more setTimeout events to the callback que until the programm crashes.
1 possible solution could be to use promises:
async function sleep(ms) {
return new Promise(res => {
setTimeout(res, ms)
})
}
async function sleep(ms) {
return new Promise(res => {
setTimeout(res, ms)
})
}
async function main() {
console.log("waiting 5 seconds without blocking the main thread")
await sleep(5000)
console.log("done")
}
main()
The problem is that you are generating an infinite loop, as the durationInput doesn't update until the setTimeout executes. And you are filling the execution stack with a huge cue.
For fixing it, you need to create a variable that will store the initial value of the durationInput and subtract from duration in the while loop.
function countdown(duration, intervalInSeconds = 1) {
let count = duration;
while (duration > 0) {
setTimeout(() => {
console.log(count--);
}, intervalInSeconds * 1000);
duration--;
}
}
countdown(10);