0

I have three functions that I want to run in sequence (and then repeat, but I'm not even on that yet.) So when the first function displays its content and then leaves, the second function will play afterwards and do the same thing. Then that repeats into the third function. I'm using callbacks to try to achieve this.

This isn't a problem when I'm using only two functions, but when I introduce the third, It renders the first two menu boards, and then the third one comes afterwards, when they should render 1, 2 and then 3.

JavaScript for Reference

$(document).ready(function(){

        Board1 = function(callback){
            $('#menu-board .board.one .row').slideDown(800).delay(10000).slideUp(800, function(){
                callback();
            });
        }
        Board2 = function(callback){
            $('#menu-board .board.two .row').slideDown(800).delay(10000).slideUp(800, function(){
                callback();
            });
        }
        Board3 = function(){
            $('#menu-board .board.three .row').slideDown(800).delay(10000).slideUp(800);
        }

        Board1(Board2(Board3)); 

});

Any help is appreciated. Thank you.

1
  • 2
    Because Board2(Board3) will just start Board2 imediately. Commented Aug 16, 2015 at 16:12

2 Answers 2

3
Board1(Board2(Board3));

is equal to:

var res = Board2(Board3);
Board1(res);

So it won't act as you expect, it just start to execute Board2, and then start Board1, so Board3 is only guranteed to execute after Board2, while the order of Board1 is not relevant to Board2 and Board3.

You can use .bind to create a function that calls Board2 with give param Board3 like:

Board1(Board2.bind(null, Board3)); 

or just wrap them in another function:

Board1(function() {
    Board2(Board3);
}); 

However, if you have too many functions to chain, use the methods above may not be a good idea, then you may create a chainer to do what you want:

// This function will accept a sequnce of functions in array, execute them in order, and call the done callback when all is complete.
var chain = function(sequences, done) {
  // Manage the current index, and total items that would be called.
  var idx = 0, length = sequences.length;
  var caller = function() {
    // When all functions in sequence is called, call final callback to notify user
    // you may have to check if done is a function or not.
    if (idx === length) {
      if (typeof done === 'function') {
        done();
      }
      return;
    }
    // Get the next function to call.
    var currentTarget = sequences[idx];
    // Pass caller to the target function, so when the function completes and call the callback
    // the caller can takeover and start to call next function in sequence.
    currentTarget(caller);
    ++idx;
  };

  caller();
};


// Create some test cases.
var sequence = [], i;
for (i = 0; i < 10; ++i) {
    // Create some functions that will display some text after 1 sec when it get called.
    sequence[i] = (function(index) {
        return function(cb) {
            setTimeout(function() {
                var div = document.createElement('div');
                div.innerHTML = 'Index is: ' + index;
                document.body.appendChild(div);
                cb();
            }, 1000);
        };
    }(i));
}

// Demo.
chain(sequence, function() {
    document.body.appendChild(document.createTextNode("All done."));
});

By the chain function above, you can now use it as chain([Board1, Board2, Board3]) and it keeps the codes simple even if you have a sequence of many functions.

PLUS:

From .slideUp()'s document:

Callback Function

If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments, but this is set to the DOM element being animated. If multiple elements are animated, it is important to note that the callback is executed once per matched element, not once for the animation as a whole.

As of jQuery 1.6, the .promise() method can be used in conjunction with the deferred.done() method to execute a single callback for the animation as a whole when all matching elements have completed their animations ( See the example for .promise() ).

So if there's more than 1 element match to animate, the callback in your current function will get called more than once, you may have to rewrite your function with what the doc suggest to

 Board1 = function(callback){
     $('#menu-board .board.one .row').slideDown(800).delay(1000).slideUp(800).promise().done(callback);
 }

You can see the jsfiddle that work as you expect.

Sign up to request clarification or add additional context in comments.

2 Comments

This seems to be on the right path, but when the third board is called, the second board also shows up with it.
@user1757979 Updated my answer, added the reason why you met that issue and the solution to it, with jsfiddle demo.
0

why dont you just call the callback function directly in the slideup function.somewhat like this:

$('#menu-board .board.one .row').slideDown(800).delay(10000).slideUp(800, callback);

let me know if this does not work.

This is the reference for slideup function:

http://api.jquery.com/slideup/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.