【问题标题】:Could using native browser modal dialogs in a loop lead to potentially infinite execution?在循环中使用本机浏览器模式对话框会导致潜在的无限执行吗?
【发布时间】:2021-02-06 16:58:12
【问题描述】:

我在 JSBin 上尝试了一些代码并得到了奇怪的结果。这应该可以工作 - 这是一个使用Window.prompt 的简单循环。它确实使用 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}`);
}

然而on JSBin it only runs for one iteration。如果打开浏览器控制台,会有警告信息:

在第 1 行退出潜在的无限循环。要禁用循环保护:在代码中添加“// noprotect”

这让我想知道......什么潜在的无限循环?对我来说,似乎没有任何东西可以导致无限执行。代码唯一“奇怪”的地方是通过prompt 的模态对话框。我尝试使用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}`);
}

the same thing happens on JSBin as before - 执行单个循环,控制台中显示相同的警告。

删除模态对话框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}`);
}

那么,JSBin 使用的分析是否正确 有一个模态对话框会导致无限循环,如果是这样 - 这如何以及何时会发生?还是这只是误报?

【问题讨论】:

  • 我相信这是浏览器为防止网站阻止您退出页面而采取的措施。没有无限循环,但您调用prompt 太快了。我正在尝试找到明确说明的位置,但同时您可以查看here
  • 其实这可能是jsbin使用的库创建的度量。一些库将终止一个耗时超过 X 秒的脚本,作为确定循环是否退出的启发式方法。提示用户输入几乎肯定需要比这个限制更长的时间。如果您将其复制/粘贴到浏览器中,它运行良好。
  • @c1moore 这对我来说很有趣,因为它似乎与浏览器无关。 Firefox 和 Chrome 可以正常使用 Stack Snippets 中的代码,但问题出现在 JSBin 上并且被报告但运行器在那里。所以这是在那里进行的某种分析,而不是在我的本地机器上。我知道您不应该使用这些,但我对浏览器创建和管理的模态对话框一无所知会导致无限循环。更糟糕的是,您可能会得到一个对话框,并且代码会继续执行。
  • @c1moore 你是对的! It's indeed just the timeout - 显然,它设置的非常低 - 我在执行之间添加了 100 毫秒的延迟,并再次获得了“潜在的无限循环”。你想添加一个答案吗?我会等到明天自己添加一个。

标签: javascript loops infinite-loop jsbin


【解决方案1】:

问题不在于您正在使用浏览器的对话框创建无限循环,JSBin 用于执行脚本的库使用超时作为启发式方法来检查无限循环。

查看控制台,我们可以看到这个超时是在runner.js 中定义的。 JSBin 的 GitHub 存储库实际上解释了这是如何完成的 (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.

不幸的是,我找不到重写循环的代码,但它很可能会重写你的循环,看起来像

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}`);
}

【讨论】:

    猜你喜欢
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多