Hi everyone, I am a beginner in javascript and am running into a small issue. In the code snippet below, the desired result is a countdown from 5 to 0 using alert messages. But for some reason it alerts only -1, why is that and how can I fix this issue. Thanks a lot in advance.

function countdown (num) {
               for (var i = 0; i <= num; i += 1) {
                   setTimeout(function () {
                   alert(num - i);
                    }, i * 1000);
               }
            }
           countdown(5);

Recommended Answers

All 2 Replies

Ash,

The reason you only ever see -1 is that in all cases, by the time the alert() statement executes, i has incremented to 6 (the exit condition for the for loop), thus num - i is -1 . When each delayed function executes, it uses the extant (then existing) value of i (ie. 6), not the value at the time the delayed funtion was put in place.

A couple of ways to overcome this come to mind (I'm sure there are others):

1. Use closures to capture the correct value to be alerted.

function countdown(num) {
	function alertLater(n){
		return function(){ alert(n); }
	}
	for(var i=0; i<=num; i++) {
		setTimeout(alertLater(num-i), i * 1000);
	}
}
countdown(5);

In this approach, alert functions are all scheduled at the outset, with different delays and with a sneaky technique for remembering, independently, the value that is to be alerted. 'Closure' is a feature of Javascript by which a "snapshot" of values is saved for later use. Note how alertLater returns a function, which, when it executes, uses the value of n passed to alertLater as a parameter even though alertLater has completed and returned.

We often form closures without realising it (and this is often inconsequential). What is maybe not too obvious, is that your original code formed a closure, but there was only one closure for all delayed alerts ... hence always the same value of -1 .

2. Use recursion rather than a loop.

function countdown2(num) {
	if(num > 0){
		setTimeout(function(){countdown2(num - 1);}, 1000);
	}
	alert(num);
}
countdown2(5);

In this approach, alert functions are scheduled in cascade. countdown2 first decides whether the terminal condition has been met. If not, then it schedules a future call to itself, countdown2 , with decremented argument. It also unconditionally alerts its un-decremented argument.

Javascript is not a simple language for beginners as might at first appear to be the case. I was fooled for about 10 years and I'm still learning.

Have fun.

Airshow

Thanks a lot Airshow.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.