setTimeout内部调用的函数没有被调用

Function called inside setTimeout isn't being called

本文关键字:调用 内部 setTimeout 函数      更新时间:2023-09-26

我有一个小的JavaScript代码,其中我试图使用setTimeout等待一些外部输入到达(通过responseReceived变量),或等待最大阈值时间,然后退出。

代码如下:

var MAX_WAIT_THRESHOLD = 5000;
var keepWaiting = true;
var waitInterval = 500;
var totalTimeWaited = 0;
alert("Alert1");
while(keepWaiting == true) {
  setTimeout(function() {
    totalTimeWaited = totalTimeWaited + waitInterval;
    alert("Alert2");
    if(responseReceived == true || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
      keepWaiting = false;
    }
  }, waitInterval);
}

问题是由于某种原因setTimeout(..)从来没有真正调用内部创建的匿名函数。我通过在Chrome的JavaScript执行控制中放置断点来检查这一点,并且执行实际上从未停止在匿名函数内放置的任何断点。JavaScript的执行一直在while ..行和setTimout(..)行之间切换。responseReceived在代码的其他地方设置。另一种说法是,第一个警报显示(Alert1),但第二个警报从未显示(Alert2)。

我做错了什么?

编辑:

我看了报告的"重复"问题,但我看不出这与我的问题有什么关系。我的问题不是关于while循环。而是关于为什么内部匿名函数没有被调用。

你的代码杀死了我的浏览器选项卡。: D

为什么不直接使用setInterval而去掉while循环呢?

var MAX_WAIT_THRESHOLD = 5000;
var waitInterval = 500;
var totalTimeWaited = 0;
var waiting = true;
alert("Alert1");
var interval = setInterval(function() {
    totalTimeWaited += waitInterval;
  alert("Alert2");
  if (responseReceived || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
    // stop waiting
    clearInterval(interval);
    waiting = false;
    alert("Done");
  }
}, waitInterval);

这个问题与javascript并发模型有关。

据我所知,所有的setTimeout回调只能在while循环结束后执行,因为while循环是一个阻塞队列的消息。但在这种情况下,它永远不会结束。有另一个SO线程解释这个,但我现在找不到它。

我看到你实际上是在用控制变量控制循环的最大时间。然而,由于这个控制代码是在setTimeout回调中,它不会被推入队列,直到循环结束,所以控制变量keepWaiting永远不会在循环中变为false。如果将控制代码置于setTimeout函数之外,它不会破坏浏览器,并且会在某些时候显示'alert2'消息-实际上是几次-:

var MAX_WAIT_THRESHOLD = 5000;
var keepWaiting = true;
var waitInterval = 500;
var totalTimeWaited = 0;
var responseReceived = false;
console.log("Alert1");
while(keepWaiting == true) {
 setTimeout(function() {
console.log("Alert2");
}, waitInterval);
   totalTimeWaited = totalTimeWaited + waitInterval;
   if(responseReceived == true || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
  keepWaiting = false;
    }   
}

但是,由于前面暴露的原因,所有回调都会在最后触发。

如果你想要一个settimeout的永恒循环,使用递归而不是迭代。