I was trying some code at JSBin and got weird results. This should work - it's a simple loop that uses Window.prompt
. It does execute the correct number of times using Stack Snippets:
for (let i = 0; i < 3; i++) {
console.log(`i: ${i}`);
let foo = prompt('Enter anyting - it will be echoed.');
console.log(`echo: ${foo}`);
}
Yet on JSBin it only runs for one iteration. If you open the browser console, there is an warning message:
Exiting potential infinite loop at line 1. To disable loop protection: add "// noprotect" to your code
Which made me wonder... What potential infinite loop? To me, there doesn't seem to be anything that can lead to infinite execution. The only "odd" thing about the code is the modal dialog via prompt
. I tried using Window.alert
:
for (let i = 0; i < 3; i++) {
console.log(`i: ${i}`);
alert("maximum three alerts");
let foo = "some input";
console.log(`echo: ${foo}`);
}
And the same thing happens on JSBin as before - single loop executed with the same warning showing in the console.
Removing the modal dialog does lead to the loop executing normally.
for (let i = 0; i < 3; i++) {
console.log(`i: ${i}`);
let foo = "some input";
console.log(`echo: ${foo}`);
}
So, is the analysis JSBin uses correct that having a modal dialog can lead to an infinite loop and if so - how and when can that happen? Or is this just a false positive?
The issue isn't that you're creating an infinite loop using the browser's dialogs, the library JSBin uses to execute your script uses a timeout as a heuristic to check for infinite loops.
Looking in the console, we can see this timeout is defined in runner.js. The GitHub repo for JSBin actually explains how this is done (render.js):
// Rewrite loops to detect infiniteness.
// This is done by rewriting the for/while/do loops to perform a check at
// the start of each iteration.
Unfortunately, I haven't been able to find the code that rewrites the loops, but chances are it rewrites your loop to look something like
let loopStart = Date.now();
for (let i = 0; i < 3; i++) {
if ((Date.now() - loopStart) >= MAX_LOOP_DURATION) {
loopProtect.hit();
break;
}
console.log(`i: ${i}`);
let foo = prompt('Enter anyting - it will be echoed.');
console.log(`echo: ${foo}`);
}