我现在一直在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)
并在延迟函数完成执行后重新启动它,但是“更多的代码”似乎一旦执行就被执行了。
如何解决这个问题?请举例说明详细解释。
答案 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
循环来创建动画。
创建一个javascript对象数组,代表时间轴中的每个步骤
在单个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>
答案 2 :(得分:0)
如果没有回调,你就无法在javascript中做延迟。
var loop;
var count;
loop=setInterval(start,30);
function start()
{
//Some code
setTimeout(function(){
//Some more code
}, 10000);
}
理想情况下,您的动画方法会有一个类似“已完成”或类似
的回调答案 3 :(得分:0)
我觉得设置函数并在其中执行任何操作都比较清晰,然后将延迟操作传递给外部setTimeout(),如下所示:
function delayedFn() {
//whichever to do here..
}
//set the timing..
setTimeout(delayedFn(){
}, 10000);
&#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)
在某个时间点或销毁时停止重复执行