首页 > 解决方案 > 使用 setTimeout 询问用户是否要等待或退出,但回调永远不会触发

问题描述

更新

解决了,有点。问题在于 Javascript 的单线程特性以及我对其事件模型的误解。循环不会被超时中断。

因此,解决方案是,我不使用回调,而是在开始循环之前获取时间戳,然后每次通过循环进行比较。如果超过 X 秒,我会触发confirm对话框:

let start = new Date();
...
while ( keepGoing && matchNotFound )
{
  ...
  let end = new Date();
  if ( end - start > 10000 )
  {
    keepGoing = confirm( "This run seems to be taking a while - keep going?" );
    start = end;
  }
}

可能不是最有效或最惯用的解决方案,但它适用于我的目的。

原来的

我试图通过 调用一个函数setTimeout,但无论我使用什么时间间隔,回调都不会触发。我不知道问题是否在于我如何设置呼叫,或者我对如何使用它的理解完全错误。

我正处于自学 Javascript 的早期阶段,并且已经编写了 Dawkins 的 Weasel 程序的一个版本作为练习。根据参数的不同,算法可能需要很长时间才能运行,所以我的想法是使用 setTimeout 调用一个函数,询问用户是否要继续并给他们保释的选项,有点像这样:

var keepGoing = true; // flag to continue main loop
var timeoutId;        // stores result of setTimeout
...
/**
 * Asks the user if they want to continue. If they do, reschedule this function to 
 * execute again after 5 seconds.
 */
function alertFunc()
{
  keepGoing = confirm( "This is taking a while - do you want to continue?" );
  if ( keepGoing )
  {
    timeoutId = setTimeout( alertFunc, 5000 );
  }
}

/**
 * Simulation loop
 */
function doWeasel()
{
  /** simulation setup */

  timeoutId = setTimeout( alertFunc, 5000 );

  /** Loop until we find a match or the user gets bored */
  while ( keepGoing && matchNotFound )
  {
    /** do the thing */
  }
  clearTimeout( timeoutId );

  /** some cleanup */
}

无论如何,这是基本的想法。该doWeasel函数与 HTML 文档中表单中的按钮单击相关联:

<html>
  <head>
    <!-- header stuff -->
  </head>
  <body>
  <!-- long-winded explanation -->

  <div class="formarea">
    <form class="inputForm">
      <!-- form stuff -->
      <input type="button" value="OK" onclick="doWeasel()"/>
      <input type="reset"/>
    </form>
  </div>
  <div id="outputarea">
    <h2>Output from the thing</h2>
    <script type="text/javascript" src="weasel.js"></script> <!-- source for doWeasel() -->
  </div>
</body>
</html>

我遇到的问题是它alertFunc似乎永远不会触发 - 我添加了控制台日志记录以在输入函数时写入一条消息,但它永远不会出现。我已经在 Chrome 中运行了调试器,并在回调中设置了一个断点,但它从未到达过。

setTimeout显然,无论是调用本身还是我尝试使用它的方式,我都做错了,但根据我迄今为止阅读的文档,我看不出它可能是什么。我对如何使用它的概念是完全错误的吗?

我是一个老 C 和 C++ 程序员,只涉足 HTML 和 Web 脚本编写,所以我可能只是不明白在这里做事的正确方法。

编辑

为了解决一些评论,这是一个工作页面 - 当我单击OK模拟运行并动态构建输出表时。只是输入参数的组合导致它运行时间过长(直到浏览器抛出“此页面无响应”或我只是关闭选项卡)。

我可以在 Chrome 的调试器中跟踪脚本的执行,它调用setTimeout并分配一个值给timerId,但回调从未真正执行。对于默认参数,模拟运行完成并在页面上构建一个包含结果的表格。

也许这不是解决问题的正确方法 - 也许我需要添加另一个按钮来调用不同的功能keepGoing设置false

编辑2

我写了一个快速而肮脏的原型来测试超时功能,我想我知道我的问题是什么。如果我不在循环中间,回调按预期执行,但如果我有一个循环旋转它不会。所以,我需要做一些关于如何处理异步事件处理的阅读。

标签: javascriptsettimeout

解决方案


如果您确定 while 循环没有阻止下一行运行,则可能脚本尚未加载,并且在您将onclick属性分配给<input>元素时尚未定义函数,请尝试设置defer标记到您的脚本元素,以确保在文档被解析后执行脚本。否则在外部调用该函数可以正常工作。


推荐阅读