I have a piece of code which blocks the event loop and waits of N milliseconds:
function sleep(milliseconds) {
var start = new Date().getTime()
console.log(`start: ${start}`)
for (var i = 0; i < 1e7; i++) {
const delta = new Date().getTime() - start
console.log(`milliseconds passed: ${delta}`)
if (delta > milliseconds) {
console.log('exiting')
console.log(`final delta: ${delta}`)
break
}
}
}
sleep(5000)
console.log('the end')
When I run it (in browser or Node) I get the expected result:
‘start’ output, bunch of ‘milliseconds passed’, and then N milliseconds later I get ‘exiting’ and ‘the end’. No problem here.
But when I comment out console.log(`milliseconds passed: ${delta}`) in the body of the for loop:
function sleep(milliseconds) {
const start = new Date().getTime()
console.log(`start: ${start}`)
for (var i = 0; i < 1e7; i++) {
const delta = new Date().getTime() - start
// console.log(`milliseconds passed: ${delta}`)
if (delta > milliseconds) {
console.log('exiting')
console.log(`final delta: ${delta}`)
break
}
}
}
sleep(5000)
console.log('the end')
I get totally surprising results:
I see ‘start’ output as before, but then it returns immediately and outputs ‘the end’. So it’s like for loop didn’t run at all or stopped running for some reason and program never went into if statement that prints ‘exiting’. The only thing that changed between the two snippets of code is commented out console.log statement, and yet behaviour changed drastically.
Can anyone please explain what is going on here?
>Solution :
The loop ran, it just ran quickly, since the bulk of the time-consuming work it does is the console.log that you’re commenting-out. It doesn’t take a modern JavaScript engine long at all to loop a million times, even if it is creating an object on each iteration (the Date). You can tell if you look for side-effects, like the final value of i (since you’re using var, we can see that value when the loop is over):
function sleep(milliseconds) {
const start = new Date().getTime();
console.log(`start: ${start}`);
for (var i = 0; i < 1e7; i++) {
const delta = new Date().getTime() - start;
// console.log(`milliseconds passed: ${delta}`)
if (delta > milliseconds) {
console.log("exiting");
console.log(`final delta: ${delta}`);
break;
}
}
if (i === 1e7) {
console.log(`Reached main termination condition after ${Date.now() - start}ms`);
}
return i;
}
const result = sleep(5000);
console.log(`The end, result = ${result}`);
On my machine, that loop completes because i reaches 1e7 in just under a second — well before the five seconds are up.
A couple of things worth noting:
- It’s best practice not to have busy-loops like this in real code. 🙂
new Date().getTime()can be replaced withDate.now(), which gives you the same thing without an object allocation. All modern and even many obsolete browsers (such as IE9+) support it.