0

我的班级中有两个功能。首先触发超时并循环它(像间隔一样工作),然后是 clearTimeout。我的问题是, clearTimeout 不起作用。我该如何解决?

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

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

例如,我想在点击时运行这些功能。

4

3 回答 3

1

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

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);
}
于 2017-08-25T20:02:01.770 回答
0

让我知道这是否适合您:

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

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

所以基本上我已经重用了@Michael Horn 的解决方案。而且,我很高兴将此答案用作他编辑的答案(如果问题解决了)。

于 2017-08-25T20:19:30.740 回答
0

如果您使用 setTimeout 或 setInterval 并希望能够取消它们,则需要将此函数的返回值保存在变量中。返回值是一个处理程序,可以在 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 的返回值,稍后与 clearTimeout 一起使用。


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


关于动画的一句话:它们很棘手!不要使用 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 的精度。它适用于时差

于 2017-08-25T20:40:04.023 回答