14

I have two javascript functions that are called from android. After long debug sessions finally I realized that the problem is arising from the fact that second function is getting called before first one is finished. I already searched the examples with deferred etc, but they all depends on function calls within another one.

function FunctInit(someVarible){ //someVariable is sent from android, cannot call again from getResult
//init and fill screen
}

function getResult(){ //also getResult need to be called from android via button
//return some variables
}

How can I force getResult to wait FuncInit? Is there a way to achieve this via Javascript?

tugce
  • 651
  • 3
  • 13
  • 28
  • Could you set a isInitialized flag and sleep in getResult if it hasn't been flipped yet? – Andrew Walters Jul 09 '14 at 14:05
  • 1
    Does `FunctInit` perform some _asynchronous_ action which you also wish to wait for the completion of? – Paul S. Jul 09 '14 at 14:06
  • @PaulS. yes it also calls two functions needs to be finished before getResult – tugce Jul 09 '14 at 14:08
  • 1
    You may want to read stuff about "callbacks". Check this out for example: http://recurial.com/programming/understanding-callback-functions-in-javascript/ It's tricky to understand but powerful, and certainly a good solution for your problem. – Lord Grosse Jeanine Jul 09 '14 at 14:11
  • I hope you mark down answer so further i dont want to post there see here for http://stackoverflow.com/questions/12116505/wait-till-a-function-is-finished-until-running-another-function – Anto king Jul 09 '14 at 14:11
  • @AntoKing marked down because I indicated clearly in my question two function is called via android, they shouldn't call each other within javascript – tugce Jul 09 '14 at 14:13

3 Answers3

47

In my opinion, deferreds/promises (as you have mentionned) is the way to go, rather than using timeouts.

Here is an example I have just written to demonstrate how you could do it using deferreds/promises.

Take some time to play around with deferreds. Once you really understand them, it becomes very easy to perform asynchronous tasks.

Hope this helps!

$(function(){
    function1().done(function(){
        // function1 is done, we can now call function2
        console.log('function1 is done!');

        function2().done(function(){
            //function2 is done
            console.log('function2 is done!');
        });
    });
});

function function1(){
    var dfrd1 = $.Deferred();
    var dfrd2= $.Deferred();

    setTimeout(function(){
        // doing async stuff
        console.log('task 1 in function1 is done!');
        dfrd1.resolve();
    }, 1000);

    setTimeout(function(){
        // doing more async stuff
        console.log('task 2 in function1 is done!');
        dfrd2.resolve();
    }, 750);

    return $.when(dfrd1, dfrd2).done(function(){
        console.log('both tasks in function1 are done');
        // Both asyncs tasks are done
    }).promise();
}

function function2(){
    var dfrd1 = $.Deferred();
    setTimeout(function(){
        // doing async stuff
        console.log('task 1 in function2 is done!');
        dfrd1.resolve();
    }, 2000);
    return dfrd1.promise();
}
Antoine Cloutier
  • 1,330
  • 11
  • 23
  • Why do you wrap your functions in `$.when()`? There is no need. You can just do `function1().done()` - no need for `$.when()` there at all. `$.when()` is used when you have several promises and you want to know when they are all done, but provides no use at all when only passing it one promise. – jfriend00 Jul 09 '14 at 18:09
  • You are very right, I had multiple promises at first and I just forgot to remove the `$.when`. I noticed it pretty much at the same time you commented. Thanks for pointing it out! – Antoine Cloutier Jul 09 '14 at 18:11
  • Thank you very much for the example. It is a very good approach to explain through a simple example @AntoineCloutier – samsri Sep 18 '15 at 14:28
  • 1
    I am sorry I don't really understand how it works, so I just follow the example. When I call the function with .done , I get error "Cannot read property 'done' of undefined". – chourn solidet Dec 30 '16 at 02:48
  • 1
    hi @AntoineCloutier I'm not really understand about deferred but just want to know why you still using timeout instead of using deferred only? – Fai Zal Dong Aug 11 '17 at 10:26
  • @AntoineCloutier This is really well written and explained, I was able to copy your example, remove the timeouts and make it work perfectly for an AJAX handler I needed. Usually I would not comment out of context but I wanted to thank you as now I have a very clear understanding of how done(), resolve(), and promise() work, prior to your post I was [keyword_stuff] "chaining setTimeout to handle race conditions" (I will never do that again seeing how lazy it is). Thank you. – Christian Žagarskas May 31 '18 at 16:39
  • @AntoineCloutier Can you take a look at this question https://stackoverflow.com/q/56397604/4425004 with this current solution? – Pranesh Janarthanan Jun 07 '19 at 11:42
6

There are several ways I can think of to do this.

Use a callback:

 function FunctInit(someVarible){
      //init and fill screen
      AndroidCallGetResult();  // Enables Android button.
 }

 function getResult(){ // Called from Android button only after button is enabled
      //return some variables
 }

Use a Timeout (this would probably be my preference):

 var inited = false;
 function FunctInit(someVarible){
      //init and fill screen
      inited = true;
 }

 function getResult(){
      if (inited) {
           //return some variables
      } else {
           setTimeout(getResult, 250);
      }
 }

Wait for the initialization to occur:

 var inited = false;
 function FunctInit(someVarible){
      //init and fill screen
      inited = true;
 }

 function getResult(){
      var a = 1;
      do { a=1; }
      while(!inited);
      //return some variables
 }
Nicholas
  • 1,974
  • 4
  • 20
  • 46
  • timeout wouldn't work in my case, since I am relying on returns from javascript function on android. But, thanks for the answer – tugce Jul 10 '14 at 11:08
2

Following answer can help in this and other similar situations like synchronous AJAX call -

Working example

waitForMe().then(function(intentsArr){
  console.log('Finally, I can execute!!!');
},
function(err){
  console.log('This is error message.');
})

function waitForMe(){
    // Returns promise
    console.log('Inside waitForMe');
    return new Promise(function(resolve, reject){
        if(true){ // Try changing to 'false'
            setTimeout(function(){
                console.log('waitForMe\'s function succeeded');
                resolve();
            }, 2500);
        }
        else{
            setTimeout(function(){
                console.log('waitForMe\'s else block failed');
                resolve();
            }, 2500);
        }
    });
}