5

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);
    }       
Hazem
  • 85
  • 1
  • 2
  • 9

4 Answers4

3

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()

Community
  • 1
  • 1
bluehallu
  • 10,205
  • 9
  • 44
  • 61
  • Seems like what I've been trying to do is very wrong and won't work like I expected. I used callbacks before, but I have to write code for each photo and it gets really nested and hard to add more in the future! Isn't there another way? – Hazem Aug 19 '13 at 11:05
  • Noone said asynchronous programming was easy! :) You don't need to write code for each photo, you can just write a normal function that takes parameters and use a callback with parameters! – bluehallu Aug 19 '13 at 11:08
  • could you please show me an example? I can't seem to understand your suggestion. I know how to use callbacks, but there must be code in a callback function and the loop would still run anyway. I'm just going to have 3 callbacks running at the same time – Hazem Aug 19 '13 at 11:15
  • 1
    Of course, you don't want to use a loop here. The callback to the first animation should be a function that triggers the second animation, and so on. – bluehallu Aug 19 '13 at 11:17
1

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
Tomalak
  • 332,285
  • 67
  • 532
  • 628
0

one thing you can do, is to use an identifier (boolean) and then, in the loop, you test the identifier to decide if the loop can continue or stop. For example, function galleryAnimation(i, iBool){ $("#pic" + i).delay(delayTime).fadeIn(duration);
iBool = 0; }

Then on the return;

for (var i=2; i<=4; i++){
    galleryAnimation(i, iBool); 
    // If iBool = 0 then continue
    // Else Break
}

that might be a solution, as the loop will need the returning value to determine the next step, to continue or break.

Nadeem_MK
  • 7,533
  • 7
  • 50
  • 61
0

I came with my own solution that seemed to work perfectly, this is my code:

function fadeInAnimation(index){
        $("#pic" + index).delay(delayTime).fadeIn(duration, function(){
            photoIndex();
        });
    }

    function photoIndex(){
        index++;
        fadeInAnimation(index);
    }
    fadeInAnimation(index);
});

I have realized that using loops is a really bad idea with things like this. This code will allow me to add as many images as I want just by renaming them in the folder rather than coding them in manually as callbacks for each photo. Thanks for those who answered. Your suggestions are great and will definitely remember them in other applications like this one

Hazem
  • 85
  • 1
  • 2
  • 9