1

Currently, when the user clicks on a button, several javascript functions get executed. Because every function does some animation (more information on this can be found in the second comment) on the site, I have to execute them one after another so jQuery will not mess up because it started an animation on an element that isn't even loaded / displayed yet.

My current solution is to call every function a bit later then the previous one by using setTimeout like this:

window.setTimeout(functionA,250);
window.setTimeout(functionB,500);

This works great in Chrome, but in Firefox things are still executed too fast sometimes. So I'm looking to fix this workaround by telling Javascript to only execute the next function when the previous one has completely finished.

I've already read about adding a callback - but I got a lot of functions to call. Do I really have to add a callback to every single function to achieve what I want?

Many thanks in advance.

JoelP
  • 439
  • 1
  • 3
  • 13
  • 1
    Please share your animation function.. – Bla... Aug 19 '14 at 12:32
  • The goal of all functions: Load some information via AJAX, add them to a dropdown menu (`.html()`), sort the dropdown, and finally select a specific option (`.prop()`). 4 steps, 4 functions. If any of the functions hasn't finished when the next one gets executed, it - obviously - won't work correctly because the last step is missing. – JoelP Aug 19 '14 at 12:36

5 Answers5

2

If you are using jQuery animations, take look at jQuery.Deferred. It is the result of all animate functions like fadeIn(), slideDown(), animate().

You can combine few deferreds like this:

var anim1 = $('.sth').animate({left:100});
var anim2 = $('.sth2').fadeOut();
var anim3 = $('.sth4').slideDown();
$.when(anim1, anim2, anim3).then(function(){
    console.log('Animations are ready');
})
Cezary Daniel Nowak
  • 1,096
  • 13
  • 21
  • I already said this in a comment from an answer which was deleted by the author. I am not using real "animations", I just insert data with `html()` and select a dropdown version with `prop()` - all necessary steps are mentioned in my first comment in the original question. – JoelP Aug 19 '14 at 12:58
  • It doesn't matter if it's not an animation, Deferred is useful for any asynchronous action. Worth looking in to: http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ and if you want something more specific then please post your all your code so we can edit it. – Ella Ryan Aug 19 '14 at 13:02
  • As Ella Ryan say: Deferred would cover this situation. http://pastebin.com/S8GfRK5y – Cezary Daniel Nowak Aug 19 '14 at 13:10
0

Why don't you just use something like this:

$(document).ready(function(){
  $("button").click(function(){
    $.ajax({url:"demo_test.txt",success:function(result){//if your ajax request success

      $("#div1").html(result); // add the result into the HTML

      Sort();//do sorting

      SelectOption();//select the option
    }});
  });
});
Bla...
  • 7,228
  • 7
  • 27
  • 46
  • In this example, sometimes the wrong option gets selected because the list wasn't fully sorted yet. – JoelP Aug 19 '14 at 12:45
  • Are you sure it's because the sorting hasn't finished ? Because as I know `SelectOption` will be executed after `Sort` is finished.. – Bla... Aug 19 '14 at 12:55
  • Absolutely. That's why I added the `setTimeout` to every function so it doesn't get messed up anymore like before. But this was just a basic example. Sometimes I have to do another AJAX request after `SelectOption` which reads the selected option from the dropdown - and without waiting, it either reads no or the wrong selected version. – JoelP Aug 19 '14 at 13:00
0

You could try using $.when() and $.then(). I don't know what your code is exactly but using your example, something like this:

$.when(functionA).then(functionB);

That would make sure A is done before B, rather than using an arbitrary timeout.

EDIT: Actually thinking about it, this may not work for you. I'd recommend looking into Deferred and Promise in jQuery, which can help you manage asynch actions without all the callbacks.

Ella Ryan
  • 1,155
  • 10
  • 23
0

You have to add callbacks, since javascript timers are not reliable.

I recommend reading the following article: How JavaScript Timers Work

Brankodd
  • 831
  • 9
  • 21
0

I've run into this problem a lot. If there's a better way to do it, I haven't found it because JS wants to run as fast as possible so it tries to execute as much as it can "at the same time".

The only thing you can do differently is make the functions return a value that must be used in the next function.

So...

// This should complete first
function a(target){
    $(target).css('color','black');
    var return_this = a + 1;
    return return_this;
}

// This should complete second
function b(target,a){
    var return_this = a + 1;
    $(target).css('color','white');
    return return_this;
}

// This should run third
function c(target,b){
    var return_this = b + 1;
    $(target).css('color','grey');
    return return_this;
}


$('a').click(){
    var a = a(this);
    var b = b(this,a);
    var c = c(this,b);
    $(this).attr('data-temp',c);
}

This is theoretical, since I worked on this issue a few months back and don't have access to it right now. You may need to play around with it a little to get it to work.

Travis Heeter
  • 13,002
  • 13
  • 87
  • 129