如何在Javascript中延迟setInterval?

时间:2015-04-05 08:37:02

标签: javascript html5 canvas delay setinterval

我现在一直在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'部分,在'动画代码'执行时什么也不做,然后执行'更多代码'部分。

正在发生的是“更多代码”部分和延迟功能同时执行。我在调用延迟函数之前尝试了clearInterval(loop)并在延迟函数完成执行后重新启动它,但是“更多的代码”似乎一旦执行就被执行了。

如何解决这个问题?请举例说明详细解释。

6 个答案:

答案 0 :(得分:4)

您的delay()功能实际上并未阻止您的start()功能完成。

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

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

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

// the code here will run immediately

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

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

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

答案 1 :(得分:1)

很高兴您的问题已经整理好了。 :-)

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

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

  2. 在单个requestAnimationFrame循环中按顺序“播放”每个步骤。

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

    // 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>

答案 2 :(得分:0)

如果没有回调,你就无法在javascript中做延迟。

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

}

理想情况下,您的动画方法会有一个类似“已完成”或类似

的回调

答案 3 :(得分:0)

我觉得设置函数并在其中执行任何操作都比较清晰,然后将延迟操作传递给外部setTimeout(),如下所示:

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

答案 4 :(得分:0)

你甚至可以摆脱超时。

这可以防止在上一个函数完成之前启动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();

答案 5 :(得分:0)

此代码在第一次执行时等待 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) 在某个时间点或销毁时停止重复执行