Javascript 清除';循环';函数中超时关闭-如何返回我有能力清除的间隔id

Javascript 清除';循环';函数中超时关闭-如何返回我有能力清除的间隔id,javascript,timeout,settimeout,setinterval,cleartimeout,Javascript,Timeout,Settimeout,Setinterval,Cleartimeout,在我的类中有两个函数。第一个触发超时并循环它(类似于interval),第二个触发clearTimeout。我的问题是,clearTimeout不起作用。我怎样才能修好它 this.startMove = function() { setTimeout(function handler() { self.moveMonster(moveMonsterCallback); setTimeout(handler, self.speed); }, thi

在我的类中有两个函数。第一个触发超时并循环它(类似于interval),第二个触发clearTimeout。我的问题是,clearTimeout不起作用。我怎样才能修好它

this.startMove = function() {
    setTimeout(function handler() {
        self.moveMonster(moveMonsterCallback);
        setTimeout(handler, self.speed);
    }, this.speed);
};

this.stopMove = function() {
    clearTimeout(self.startMove());
}

例如,我想在单击时运行这些函数。

您需要将超时分配给处理程序:

this.startMove = function() {
    self.timeout = setTimeout(function handler() {
        self.moveMonster(moveMonsterCallback);
        setTimeout(handler, self.speed);
    }, this.speed);
};

this.stopMove = function() {
    clearTimeout(self.timeout);
}

编辑 正如michalgrzasko提到的,上述代码不起作用。原因是句柄分配给了错误的超时函数。外部超时只设置一次,而内部超时在递归循环中调用,因此这就是需要清除的超时

this.startMove = function() {
    setTimeout(function handler() {
        self.moveMonster(moveMonsterCallback);
        self.handle = setTimeout(handler, self.speed);
    }, this.speed);
};

this.stopMove = function() {
    clearTimeout(self.timeout);
}
然而 同样,正如michalgrzasko和其他几个人指出的,更好的解决方案是使用setInterval,因为它更容易阅读,因此更安全:

this.startMove = function() {
    self.moveInterval = setInterval(function handler() {
        self.moveMonster(moveMonsterCallback);
    }, this.speed);
};

this.stopMove = function() {
    clearInterval(self.moveInterval);
}

让我知道这是否适用于您:

this.startMove = function() {
    self.timeout = setTimeout(function handler() {
        self.moveMonster(moveMonsterCallback);
        self.startMove();
    }, self.speed);
};

this.stopMove = function() {
    clearTimeout(self.timeout);
}

所以基本上我重复使用了@Michael Horn的解决方案。而且,我很高兴使用这个答案作为他编辑的答案的补充(如果问题解决了)

如果使用setTimeout或setInterval并希望能够取消它们,则需要将此函数的returnvalue保存在变量中。返回值是一个处理程序,可以在clearTimeout或clearInterval中使用

在这种情况下,如果moveMonster函数的时间消耗比this.speed小,则setInterval会更容易

this.startMove = function() {
    this.startMove.intervalHandler = setInterval(function handler() {
        self.moveMonster(moveMonsterCallback);
    }, this.speed);
};

this.stopMove = function() { clearInterval(this.startMove.intervalHandler); }
我更喜欢使用函数作用域来保存诸如Handler之类的东西。如果不喜欢,请使用父范围或上下文

如果使用setTimeout而不是setInterval很重要,那么您可以在其他答案中找到解决方案。这完全是一样的:保存setTimeout的returnvalue,稍后再与clearTimeout一起使用


如果动画结束时应该调用moveMonsterCallback,请查看承诺而不是回调。有了回叫,你的位置越来越快,很难追踪回叫


一句关于动画的话:它们很狡猾!不要使用setTimeout。最好在窗口对象上调用requestAnimationFrame

function step(timestamp) {
  if (!step.startTime) step.startTime = timestamp;
  var delta = step.getDelta(timestamp);
  // do the calculations of how far you have to move the monster in this time range
  // move the monster...
  ...
  // animation is stopped? If not: We want to animate another timeframe
  if (!step.stopped) {
    window.requestAnimationFrame(step);
  }
}
step.startTime = null;
step.stopped = false;
step.getDelta = (timestamp)=>timestamp-step.startTime;

function stopMove() {
  step.stopped = true;
}

window.requestAnimationFrame(step);

此解决方案提供了更好的结果,因为它与setTimeout的精度无关。它可以处理时间差

可能的重复,以便更好地为页面中的某些内容设置动画。还要注意的是,setTimeout的延迟是不能保证的!当你在stopMove中调用startMove时,创建一个新的间隔可能会有所不同……PRMoureu,它是一个简单的清除间隔。我有更复杂的问题,你的建议对我不起作用,JoshuaK,谢谢,我会检查它,但现在我必须用我在上面写的方法来解决问题,你是对的。我拼命尝试所有可能的组合:)他正在创建一个新的超时处理程序,而不是间隔处理程序。我不确定它是否是故障安全的,如果
这个。速度非常小。@JoshuaK,它是安全的。
stopMove()。或者它在后面运行,清除它没有效果。JS是单线程的,所以没有并发问题。@Barmar是的。但是self.timeout只保存第一个创建的句柄,并且永远不会被处理函数内的setTimeout调用覆盖。他调用handler,而不是在第一次调用后调用this.startMove。如果我先看清楚它就不起作用了为什么需要在setTimeout中调用setTimeout?再次调用this.startMove()即可。。。;在这种情况下,self.startMove()。@82Tuskers在这种情况下,您是对的。但是如果你想在动画开始时做更多的事情,这是有意义的,但不是在每一步(显示消息“animation start”或类似的内容)。是的,这就是我需要的。我不知道为什么我要使用handler()和复杂的函数,如果这么简单的话。可能我混合了互联网上的不同解决方案。谢谢!:)您好,感谢您的广泛响应!My moveMonster函数根据monster.direction(右、左、上、下)更改monster实例的属性(例如monster.x+=1/monster.y+=-1等)。我希望每隔500毫秒更改x和y的值,并执行回调函数,从而更改DOM元素中的css。所以moveMonster不是我能制作的任何东西。我不知道如何将requestAnimationFrame与我的解决方案结合起来。我在这里粘贴代码只是为了更好地理解我的类而查看我的函数:(显然这里它不起作用)