218

I have the following JavaScript code:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable);
        function2(someOtherVariable);
    }
    else {
        doThis(someVariable);
    }
});

How can I ensure that function2 is called only after function1 has completed?

Tot Zam
  • 8,406
  • 10
  • 51
  • 76
Rrryyyaaannn
  • 2,547
  • 5
  • 19
  • 14
  • 27
    is `function1` performing an async operation? – LiraNuna Feb 15 '11 at 06:10
  • 10
    Yads, if function1 contains animations, function2 will be executed while function1's animations are still happening. How would you make function2 wait until everything started in function1 is completely done? – trusktr Mar 05 '11 at 21:45
  • Can someone explain to me why there needs to be anything done to ensure function2 is not invoked until function1 is complete? There is no asynchronous operation happening here so function2 will not run until function1 is complete anyways as this operation is synchronous. – Aaron Jun 20 '16 at 13:54
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Liam Feb 15 '18 at 16:47

10 Answers10

245

Specify an anonymous callback, and make function1 accept it:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable, function() {
          function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
  ...do stuff
  callback();
} 
Mike Robinson
  • 24,971
  • 8
  • 61
  • 83
  • 11
    +1 but if he's using 1.5 he can just use the new Deferreds pattern – philwinkle Feb 15 '11 at 06:15
  • Thanks for the quick response(s). Yes, function1 is just performing a simple asynchronous task, so I believe you're correct in that I'll have to create a callback — or take a look at this deferreds business that philwinkle has mentioned. Thanks again, guys. I'm gonna get some sleep, and tackle this again in the morning. – Rrryyyaaannn Feb 15 '11 at 06:31
  • 15
    This answer isn't the solution. Here's proof it doesn't work: http://jsfiddle.net/trusktr/M2h6e/ – trusktr Mar 19 '11 at 08:20
  • I must be missing something, because your proof looks nothing like my answer – Mike Robinson Aug 09 '12 at 17:02
  • lol, ...do stuff; callback(); is absolutely same what has author of question – OZ_ Apr 24 '13 at 19:50
  • 15
    @MikeRobinson Here's the problem: What if the `...do stuff` contains things that are asynchronous? Function2 will still not fire when expected. The example in my comment above shows that because the `foo()` function has asynchronous code in it, `bar()` does not fire it's content after `foo()`'s content is done executing, even using `$.when().then()` to call them one after the other. This answer is only valid if (and only if) all the stuff at `...do stuff` in your code is strictly synchronous. – trusktr Jul 02 '13 at 03:25
  • 2
    @trusktr In that case you need to keep passing the first callback down to the _n_ th level of asynchronous call, then fire `callBack()` after all _n_ asynchronous calls are done. Since OP has not mentioned what he is doing in the function its assumed it as one level asynchronous call. – GoodSp33d Jul 02 '13 at 04:23
  • I prefer using jquery.promise, this kind of answer will create callback hell easily – user2534365 Jul 14 '15 at 07:08
  • No, the problem here is thaat the callback is still executing at the same time of function1, and what is expected is that function2 executes after function1! – Moisés Briseño Estrello Aug 02 '22 at 18:11
107

If you're using jQuery 1.5 you can use the new Deferreds pattern:

$('a.button').click(function(){
    if(condition == 'true'){
        $.when(function1()).then(function2());
    }
    else {
        doThis(someVariable);
    }
});

Edit: Updated blog link:

Rebecca Murphy had a great write-up on this here: http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/

philwinkle
  • 7,036
  • 3
  • 27
  • 46
  • The whole point of deferreds is to *delay* execution in case something can happen asynchronously. See the very first example in the documentation for `$.when()` here http://api.jquery.com/jQuery.when and you'll understand that in that use case, it cannot logically process ajaxArgs until the `$.ajax()` call returns successful. – philwinkle Feb 15 '11 at 06:21
  • 2
    But is that a working example? What is being deferred? You're executing function1 and function2 immediately. (I'm not the original commenter.) – user113716 Feb 15 '11 at 06:22
  • As we have no idea what function1() and function2() do, then no, it's pseudo-code. `$.when()` expects a defferred object back... `$.ajax()` in 1.5 hands it back already but you can also just as easily use something to the effect of Rebecca's suggestion of `var dfd = new $.Deferred();` and return that. – philwinkle Feb 15 '11 at 06:24
  • 13
    That's not working at all for me. function1 and function2 both get executed at exactly the same time (as observable by the human eye). Here's the tiny example: http://jsfiddle.net/trusktr/M2h6e/ – trusktr Mar 19 '11 at 08:17
  • The Rebecca Murphy link didn't work for me... here's a current link for her page: http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/ – gloomy.penguin Jan 24 '13 at 19:28
  • 1
    Rebecca Murphy's write up was before Defferds were introduced to jQuery and it uses examples based on how the writer thinks it will be implemented. Please visit jQuery's site to see how to actually use this feature: http://api.jquery.com/jQuery.Deferred/ – Spencer Williams Mar 13 '14 at 16:45
  • @williamcwilliams Agreed. I'm not sure what kind of historical significance would be lost by editing this example to be more modern. I've been maintaining the link for some time, but I think it's better to link off to another question that answers this more concretely. – philwinkle Mar 13 '14 at 16:50
  • 1
    Even with jQuery 1.5 or something modern, don't you want `$.when(function1).then(function2);` (without the parentheses that call the function)? – Teepeemm Apr 10 '14 at 14:30
  • 1
    Reading these comments a few years late. `function1` should return a promise. In that case it needs to be the actual executed function, not the reference. When `resolve` is called on that promise then `function2` is executed. This is easily explained by assuming that `function1` has an ajax call. The `done` callback would then resolve the promise. I hope that's clear. – philwinkle Apr 16 '14 at 14:15
56

Try this :

function method1(){
   // some code

}

function method2(){
   // some code
}

$.ajax({
   url:method1(),
   success:function(){
   method2();
}
})
TuanTruong
  • 561
  • 4
  • 2
  • After testing several other solutions, finally it worked for me:) Thank you @TuanTruong!! You may add some texts to make this answer more useful also for other users with the same problem. – Elias Apr 22 '21 at 08:50
51

This answer uses promises, a JavaScript feature of the ECMAScript 6 standard. If your target platform does not support promises, polyfill it with PromiseJs.

Promises are a new (and a lot better) way to handle asynchronous operations in JavaScript:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable).then(function() {
            //this function is executed after function1
            function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
    return new Promise(function (fulfill, reject){
        //do stuff
        fulfill(result); //if the action succeeded
        reject(error); //if the action did not succeed
    });
} 

This may seem like a significant overhead for this simple example, but for more complex code it is far better than using callbacks. You can easily chain multiple asynchronous calls using multiple then statements:

function1(someVariable).then(function() {
    function2(someOtherVariable);
}).then(function() {
    function3();
});

You can also wrap jQuery deferrds easily (which are returned from $.ajax calls):

Promise.resolve($.ajax(...params...)).then(function(result) {
    //whatever you want to do after the request
});

As @charlietfl noted, the jqXHR object returned by $.ajax() implements the Promise interface. So it is not actually necessary to wrap it in a Promise, it can be used directly:

$.ajax(...params...).then(function(result) {
    //whatever you want to do after the request
});
Domysee
  • 12,718
  • 10
  • 53
  • 84
  • `Promise.resolve` wrapping `$.ajax` is anti-pattern since `$.ajax` returns thennable promise – charlietfl May 22 '18 at 02:10
  • @charlietfl but it is not an actual `Promise`, it just implements the interface. I'm not sure how it behaves when passing a real `Promise` to its `then` method, or what a `Promise.all` would do if a `jqXHR` and a `Promise` are passed to it. For that I need to do further testing. But thank you for the hint, I will add it to the answer! – Domysee May 22 '18 at 20:51
  • Actually in jQuery version 3+ is Promises A+ compliant. Irregardless `$.ajax.then` is not new – charlietfl May 22 '18 at 20:58
21

Or you can trigger a custom event when one function completes, then bind it to the document:

function a() {
    // first function code here
    $(document).trigger('function_a_complete');
}

function b() {
    // second function code here
}

$(document).bind('function_a_complete', b);

Using this method, function 'b' can only execute AFTER function 'a', as the trigger only exists when function a is finished executing.

Zack
  • 1,615
  • 18
  • 26
  • 1
    "As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document." http://api.jquery.com/bind/ – CodeVirtuoso Dec 19 '13 at 09:41
10

you can do it like this

$.when(funtion1()).then(function(){
    funtion2();
})
Jay Momaya
  • 1,831
  • 19
  • 32
4

This depends on what function1 is doing.

If function1 is doing some simple synchrounous javascript, like updating a div value or something, then function2 will fire after function1 has completed.

If function1 is making an asynchronous call, such as an AJAX call, you will need to create a "callback" method (most ajax API's have a callback function parameter). Then call function2 in the callback. eg:

function1()
{
  new AjaxCall(ajaxOptions, MyCallback);
}

function MyCallback(result)
{
  function2(result);
}
Russell
  • 17,481
  • 23
  • 81
  • 125
4

If method 1 has to be executed after method 2, 3, 4. The following code snippet can be the solution for this using Deferred object in JavaScript.

function method1(){
  var dfd = new $.Deferred();
     setTimeout(function(){
     console.log("Inside Method - 1"); 
     method2(dfd);  
    }, 5000);
  return dfd.promise();
}

function method2(dfd){
  setTimeout(function(){
   console.log("Inside Method - 2"); 
   method3(dfd); 
  }, 3000);
}

function method3(dfd){
  setTimeout(function(){
   console.log("Inside Method - 3");  
   dfd.resolve();
  }, 3000);
}

function method4(){   
   console.log("Inside Method - 4");  
}

var call = method1();

$.when(call).then(function(cb){
  method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
1

If function1 is some sync function that you want to turn into an async one because it takes some time to complete, and you have no control over it to add a callback :

function function1 (someVariable) {
    var date = Date.now ();
    while (Date.now () - date < 2000);      // function1 takes some time to complete
    console.log (someVariable);
}
function function2 (someVariable) {
    console.log (someVariable);
}
function onClick () {
    window.setTimeout (() => { function1 ("This is function1"); }, 0);
    window.setTimeout (() => { function2 ("This is function2"); }, 0);
    console.log ("Click handled");  // To show that the function will return before both functions are executed
}
onClick ();

The output will be :

Click handled

...and after 2 seconds :

This is function 1
This is function 2

This works because calling window.setTimeout () will add a task to the JS runtine task loop, which is what an async call makes, and because the basic principle of "run-to-completion" of the JS runtime ensures that onClick () is never interrupted before it ends.

Notice that this as funny as it makes the code difficult to understand...

StashOfCode
  • 83
  • 1
  • 6
0

I use @philwinkle code like below:

$.when(function1()).then(function2());  

But that doesn't work for me. Instead I use @Jay Momaya code like below and this works for me:

$.when(funtion1()).then(function(){
    funtion2();
})
Majid Basirati
  • 2,665
  • 3
  • 24
  • 46