清除函数中的 'looped' 超时关闭 - 如何 return 我能够清除它的间隔 ID

Clear 'looped' timeout closed in function - how to return id of interval that I would have ability to clear it

我的 Class 中有两个函数。首先触发超时并循环它(像间隔一样工作),然后是 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 并希望能够取消它们,您需要将此函数的 return值保存在一个变量中。 return-value 是一个处理程序,可以在 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 的 return 值,稍后使用 clearTimeout。


如果动画结束时应该调用 moveMonsterCallback,请查看承诺而不是回调。通过回调,您可以快速定位,很难跟踪调用。


关于动画的一句话:它们很棘手!不要使用设置超时。最好在 window 对象上调用 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 的精度无关。它适用于时差