Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling function in a loop in javascript

I am trying to call a function from within a loop in a way that when the function finishes executing, the loop continues to the next iteration and calls it again. But instead the loop doesn't wait for the function to finish and instead calls 4 instances of the function and runs them at the same time! Should I put the whole function in the loop or is there to make the loop wait for the function to be executed? Thanks

    for (var i=2; i<=4; i++){
        galleryAnimation(i); //This is executed 3 times at once
    }
    function galleryAnimation(i){
        $("#pic" + i).delay(delayTime).fadeIn(duration);
    }       
like image 247
Hazem Avatar asked Oct 04 '22 05:10

Hazem


2 Answers

The function is being executed 3 times just like you requested, the problem is that both delay and fadeIn use timers: they set a timer in the future when the function will be executed and return immediately: they are non-blocking calls. So, in your case, because you're calling the function 3 times at, let's say, 0.0001s, 0.0002s, and 0.0003s, the three kick in at, let's say, 5.0001, 5.0002 and 5.0003.

What you had in mind were blocking calls to these functions. You expected the whole execution to stop until the animations were finished. This would stop the whole browser Javascript engine for the duration, meaning no other animation or user javascript interaction would be possible.

To solve it, you have to use callbacks. You can supply a function to fadeIn that will be called once the animation has completed:

http://api.jquery.com/fadeIn/

You can use queues to simulate the same on delay():

Callback to .delay()

like image 197
bluehallu Avatar answered Oct 19 '22 10:10

bluehallu


Simplistic solution: Increase the timeout by a factor every time.

var i, factor, 
    duration = 250,
    delayTime = 500;

for (i = 2, factor = 0; i <= 4; i++, factor++) {
    galleryAnimation(i, factor);
}

function galleryAnimation(i, factor) {
    $("#pic" + i).delay(factor * delayTime).fadeIn(duration);
}

This runs the same way your approach does, only the delays get longer every time.

Generic solution 1 - work with setInterval() to have your worker function (the one that does the fadeIn) called in predefined intervals:

var elements = $("#pic2,#pic3,#pic4").toArray(),   // or any other way to select your elements
    duration = 250,
    delayTime = 500,
    intervalId = setInterval(function () {
        $(elements.shift()).fadeIn(duration);
        if (elements.length === 0) {
            clearInterval(intervalId);
        }
    }, delayTime);

Generic solution 2 - work with callbacks that are called when the previous animation finishes:

var elements = $("#pic2,#pic3,#pic4").toArray(),   // or any other way to select your elements
    duration = 250,
    delayTime = 500,
    next = function () {
        $(elements.shift()).delay(delayTime).fadeIn(duration, next);
    };

next();  // start the chain
like image 1
Tomalak Avatar answered Oct 19 '22 10:10

Tomalak