如何延迟 Javascript 中的 setInterval?

How to delay setInterval in Javascript?

我现在 运行 在 JavaScript 中反复遇到一个奇怪的问题。我似乎不能再拖延 setInterval

发生的事情的一个小例子:

var loop;
var count;
loop = setInterval(start, 30);

function start() {
    //Some code

    delay();

    //Some more code
}

function delay() {
    setTimeout(function () {
        count++;

        //Animation code

        if (count <= 1000) delay();
    }, 100);
}

现在我要做的是,执行'some code'部分,在'animation code'执行时什么都不做,然后执行'some more code'部分。

发生的事情是 'some more code' 部分和延迟函数同时执行。我在调用延迟函数之前尝试了 clearInterval(loop) 并在延迟函数完成执行后重新启动它,但是 'some more code' 似乎无论如何都执行了一次。

我怎样才能解决这个问题?请举例详细说明。

您的 delay() 函数实际上并没有阻止您的 start() 函数完成。

在Javascript中,setTimeout()不会暂停Javascript的执行。相反,它所做的是将传递给 setTimeout() 的回调安排在将来的某个时间 运行,而您的其余代码将继续 运行ning.

如果你想在一段时间内延迟执行某个代码块,那么你必须将该代码块放入 setTimeout() 回调中,如下所示:

setTimeout(function() {
    // the code in here will run some time in the future
}, delayTime);

// the code here will run immediately

Javascript 中经常描述的方式是说对 setTimeout() 的调用是非阻塞的。它不会停止或暂停当前执行线程的 运行ning。事实上那个执行线程会运行完成。相反,setTimeout() 安排一个回调函数在将来的特定时间调用(当没有其他 Javascript 代码是 运行ning 时)。

因为 Javascript 是单线程的,它几乎永远无法通过循环来尝试创建延迟,即使您使用非常长的 while() 循环也是如此。问题是当你在循环时,没有其他 Javascript 代码可以 运行 所以没有其他状态可以改变所以无论你等待改变的循环条件在你循环时都不会改变。这通常只会导致死锁类型的情况,最终浏览器意识到 Javascript 线程是 "stuck" 并会提示中止它。

相反,您使用事件和未来回调进行编程。您设置一个事件或计时器回调,以便在将来某个时间发生某事时调用它,然后将相关代码放入该回调或事件处理程序中。还有更高级的工具可以帮助管理这一点,例如 promises 或异步库,但它们只是建立在相同的回调机制之上。

如果没有回调,你真的无法在 javascript 中执行延迟。

var loop;
var count;
loop=setInterval(start,30);
function start()
{
    //Some code
    setTimeout(function(){
        //Some more code
    }, 10000);

}

理想情况下,您的动画方法应该有一个像 "completed" 或类似的回调

我发现设置函数并在其中执行任何操作更简洁,然后将延迟的操作传递给外部 setTimeout(),如下所示:

function delayedFn() {
   //whichever to do here.. 
}
  
 
    //set the timing.. 
    setTimeout(delayedFn(){
    }, 10000);

您甚至可以摆脱超时。

这可以防止在前一个函数完成之前启动您的 start() 函数。

function start() {
    animate(function(){
        someMoreCode();
    });    
}

function animate(callback) {    
    //animation code

    //once animation is done call a callback
    callback();
}
function someMoreCode(){
    //Some more code

    //once everything's done then start again
    start();
}

start();

很高兴您的问题得到了解决。 :-)

我会 post 我的“2 美分”,因为我非常喜欢使用单个 requestAnimationFrame 循环来创建动画。

  1. 创建一个 javascript 对象数组,代表时间轴中的每个单独步骤

  2. 依次 "play" 单个 requestAnimationFrame 循环中的每个步骤。

这是一个带注释的示例和演示:

// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// define step1 in the timeline
var step1={
  startX:0,
  endX:100,
  currentX:0,
  onDraw:function(){
    ctx.fillStyle='blue';
    ctx.fillRect(this.currentX,50,75,60);
  },
  onAnimate:function(){
    this.currentX++;  // or however you want myRect1 moved this frame
    if(this.currentX>=this.endX){
      this.currentX=this.endX;
      this.isCompleted=true;
    }
  },
  isCompleted:false
};

// define step2 in the timeline
var step2={
  startX:200,
  endX:100,
  currentX:200,
  onDraw:function(){
    ctx.fillStyle='gold';
    ctx.fillRect(this.currentX,50,75,60);
  },
  onAnimate:function(){
    this.currentX--;  // or however you want myRect1 moved this frame
    if(this.currentX<=this.endX){
      this.currentX=this.endX;
      this.isCompleted=true;
    }
  },
  isCompleted:false
}

// put all steps in an array
var steps=[ step1, step2 ];

// nextTime is used to trigger re-rendering
var nextTime=0;
// each animated frame will occur every 50 ms
var delayPerFrame=1000/60*3;

// start the animation loop
requestAnimationFrame(animate);

// the animation loop
function animate(time){

  // return if 50ms has not elapsed
  if(time<nextTime){requestAnimationFrame(animate); return;}

  // set the next elapsed time
  nextTime=time+delayPerFrame;

  // clear the canvas
  ctx.clearRect(0,0,cw,ch);

  // redraw all steps and also
  // find the active step in steps[] & run it's onAnimate
  var isAnimating=false;
  for(var i=0;i<steps.length;i++){
    var s=steps[i];
    if(!isAnimating && !s.isCompleted){
      s.onAnimate();
      isAnimating=true;
    }
    s.onDraw();
  }

  // request another loop if all steps are not yet completed
  if(isAnimating){
    requestAnimationFrame(animate);
  }else{
    alert('The animation is complete');
  }

}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<h4>Step1: Blue rect moves rightward<br>Step2: Gold rect move leftward.</h4>
<canvas id="canvas" width=300 height=300></canvas>

此代码首次执行时等待 initialDelay 秒,此后每 delay 秒执行一次

const initialDelay = 3
const delay = 5
let interval

setTimeout(() => {
  // call your func here
  interval = setInterval(() => {
    // call your func here
  }, delay * 1000)
}, initialDelay * 1000)

您可能希望也可能不希望使用 clearInterval(interval) 在某个时刻或销毁时停止重复执行