-1

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?

Maik Lowrey
  • 15,957
  • 6
  • 40
  • 79
VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • I believe this is a measure browsers are taking to keep websites from keeping you from exiting the page. There's no infinite loop, but you called `prompt` too quickly. I'm trying to find where this is definitively stated, but in the meantime you can look [here](https://developers.google.com/web/updates/2017/03/dialogs-policy). – c1moore Dec 29 '19 at 20:40
  • 2
    Actually, this is probably a measure created by the library jsbin uses. Some libraries will terminate a script that takes longer than X seconds as a heuristic for determining if a loop will exit or not. Prompting for user input almost certainly takes longer than that limit. If you copy/paste that into the browser, it runs fine. – c1moore Dec 29 '19 at 20:46
  • @c1moore it's interesting to me because it doesn't appear to be related to the browser. Firefox and Chrome work fine with the code in the Stack Snippets but the problem appears on JSBin and is reported but the runner there. So it's some sort of analysis being done there, not on my local machine. I'm aware that you shouldn't be using these but nothing I know of the modal dialogs created and managed by the browser will lead to an infinite loop. At worse, you might get a dialog and the code would continue to execute. – VLAZ Dec 29 '19 at 20:47
  • @c1moore You are right! [It's indeed just the timeout](https://jsbin.com/bubakapuje/1/edit?js,console) - apparently, it's set to something really low - I added a 100ms delay between the executions and got the "potentially infinite loop" again. Do you feel like adding an answer? I'd wait until tomorrow and add one myself. – VLAZ Dec 29 '19 at 20:53

1 Answers1

4

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}`);
}
c1moore
  • 1,827
  • 17
  • 27