Search code examples
javascripthtmlarraysloopsdelay

Trying to loop through images with a delay in canvas


I have 25 images I want to show really quickly, kinda like a slideshow without effects. My images are named 0 to 26.

I've tried setting a for loop and a setTimeout for the delay but the setTimeout runs only at the end of the for loop showing i = 25 at my Checkpoint.

JS:

function startAnimation(){
for(var i=0; i<25; i++){
    setTimeout(function(){
       img = new Image();
       img.src = 'images/canvas/'+[i]+'.jpg';
       img.onload = function(){ctx.drawImage(img,0,0, 850,194)} 

       alert('CP. In setTimeout. i= '+i);
    },1000);
    ctx.clearRect(0,0,canvas.width, canvas.height); //clear image after 1 sec, loop to show next.
    alert('CP outside. i = '+i);            
}

}

I followed this solution How do I add a delay in a JavaScript loop?:

function startAnimation(){
    setTimeout(function(){
        img = new Image();
        img.src = 'images/canvas/'+[counter]+'.jpg';
        img.onload = function(){ctx.drawImage(img,0,0, canvas.width,canvas.height)};
        counter++;
        if(counter<26){
            startAnimation();
        }
    },150)
}

It seems to be working like I want it to.


Solution

  • Based on the following snippet of code:

    //clear image after 1 sec, loop to show next.
    

    It appears that you have misunderstood how setTimeout works. The setTimeout function does not wait before returning. It returns immediately and schedules the code/function passed to it to execute at a later time (1 second in your case). So what your loop does is to create 25 setTimeouts that all simultaneously execute one second after the loop is executed.

    There are two solutions around this. One, to create 25 setTimeouts each one second later than the other:

    for(var i=0; i<25; i++){
        setTimeout(function(){/* ... */}, 1000 * i);
    }
    

    Alternatively to call setTimeout recursively to process your image list:

    function foo (i) {
        /* ... */
        if (i >= 0) {
            setTimeout(foo(i-1),1000);
       }
    }
    
    foo(24);
    

    The second form is more common.


    In addition to the setTimeout issue. You also need to read up on how closures work inside loops because in your loop all the setTimeouts will execute with the value of i = 24 instead of i being the values 1 to 24.

    See: Please explain the use of JavaScript closures in loops