I’m volunteering with a group running a coding bootcamp at the moment, and was looking through some of the sample code challenges that have been put together for helping the students learn to debug JavaScript. These challenges are quite simple at the moment, as they’ve only just covered the basics (variables, expressions, loops, functions etc.). As there are no model answers at the moment, I was looking at one of the questions with a view to providing one. The question runs as follows:
Find bug below and make sure it is working as expected.
Two way to handle this problem;
1- new ES6 type
2- Change logic inside loop
Desired output;
The index of this number is: 0
The index of this number is: 1
The index of this number is: 2
The index of this number is: 3
The index of this number is: 4
*/
const arr = [10, 12, 15, 21, 34];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 1000);
}
On the face of it, valid code, though when run, it outputs
// The index of this number is: 5
demonstrating that the loop and the timeout are running independently, and that by the time the first (and subsequent) setTimeout()
function has run its code, the loop has already completed, leaving i
set at 5.
Looking round to see what solutions are out there, it seems there are any number of solutions proffered, but none that I found that operate quite as I’d anticipated. I’m looking for something that operates as follows:
- Trigger routine
- 1 sec pause
- First
console.log()
appears - 1 sec pause
- Second
console.log()
appears - Etc.
Typical solutions I found were:
###Pause 1 sec, then display all
const arr = [10, 12, 15, 21, 34];
for(var i = 0; i < arr.length; i++) {
(function() {
var num = i;
setTimeout(function() {
console.log("The index of this number is: " + num);
}, 1000);
})();
}
Meets criteria, but relies on extending the setTimeout() duration
const arr = [10, 12, 15, 21, 34];
for (let i=0; i<arr.length; i++) {
setTimeout(function(){
let temp = i;
console.log("The index of this number is: " + temp);
}, 1000 * (i+1));
}
Note: This may be the model answer, but feels awkward
###Doesn’t pause before the first console.log()
const arr = [10, 12, 15, 21, 34];
for (var i = 0; i < arr.length; i++) {
(function(i){
window.setTimeout(function(){
console.log("The index of this number is: " + i);
}, i * 1000);
}(i));
}
Uses a closure, so may be too complex for the students at this stage of their learning
###Works as per the criteria, but abandons the use of a for()
loop
const arr = [10, 12, 15, 21, 34];
function start(counter){
if(counter < arr.length){
setTimeout(function(){
console.log("The index of this number is: " + counter);
counter++;
start(counter);
}, 1000);
}
}
start(0);
I actually rather like this one
###Doesn’t pause before the first console.log()
, and adds complexity
const arr = [10, 12, 15, 21, 34];
function displayNumber(i) {
setTimeout(function() {
console.log(`The index of this number (${arr[i]}) is: ` + i);
}, 1000 * i);
}
function callDisplay() {
for( var i = 0; i < arr.length; i++ ) {
displayNumber(i);
}
}
callDisplay();
Again, not one I’d anticipate the students coming up with on their own.
So I’m wondering whether I’m missing something obvious. I’ve not found anything that will pause the loop whilst the setTimeout()
does its thing, though I’ve seen several comments to say you can’t do that. Any thoughts out there on alternatives?