I have two JS functions. One calls the other. Within the calling function, I'd like to call the other, wait for that function to finish, then continue on. So, for example/pseudo code:
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
I came up with this solution, but don't know if this is a smart way to go about it.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Is that legit? Is there a more elegant way to handle it? Perhaps with jQuery?
Use async/await :
then use await in your other function to wait for it to return:
The only issue with promises is that IE doesn't support them. Edge does, but there's plenty of IE 10 and 11 out there: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (compatibility at the bottom)
So, JavaScript is single-threaded. If you're not making an asynchronous call, it will behave predictably. The main JavaScript thread will execute one function completely before executing the next one, in the order they appear in the code. Guaranteeing order for synchronous functions is trivial - each function will execute completely in the order it was called.
Think of the synchronous function as an atomic unit of work. The main JavaScript thread will execute it fully, in the order the statements appear in the code.
But, throw in the asynchronous call, as in the following situation:
This doesn't do what you want. It instantaneously executes function 1, function 2, and function 3. Loading div flashes and it's gone, while the ajax call is not nearly complete, even though
makeAjaxCall()
has returned. THE COMPLICATION is thatmakeAjaxCall()
has broken its work up into chunks which are advanced little by little by each spin of the main JavaScript thread - it's behaving asychronously. But that same main thread, during one spin/run, executed the synchronous portions quickly and predictably.So, the way I handled it: Like I said the function is the atomic unit of work. I combined the code of function 1 and 2 - I put the code of function 1 in function 2, before the asynch call. I got rid of function 1. Everything up to and including the asynchronous call executes predictably, in order.
THEN, when the asynchronous call completes, after several spins of the main JavaScript thread, have it call function 3. This guarantees the order. For example, with ajax, the onreadystatechange event handler is called multiple times. When it reports it's completed, then call the final function you want.
I agree it's messier. I like having code be symmetric, I like having functions do one thing (or close to it), and I don't like having the ajax call in any way be responsible for the display (creating a dependency on the caller). BUT, with an asynchronous call embedded in a synchronous function, compromises have to be made in order to guarantee order of execution. And I have to code for IE 10 so no promises.
Summary: For synchronous calls, guaranteeing order is trivial. Each function executes fully in the order it was called. For a function with an asynchronous call, the only way to guarantee order is to monitor when the async call completes, and call the third function when that state is detected.
For a discussion of JavaScript threads, see: https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 and https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
Also, another similar, highly rated question on this subject: How should I call 3 functions in order to execute them one after the other?
This what I came up with, since I need to run several operations in a chain.
I'm really confused about the process...considering that I have a internal function, how can I return to the outer function the result (true/false) !?!
It appears you're missing an important point here: JavaScript is a single-threaded execution environment. Let's look again at your code, note I've added
alert("Here")
:You don't have to wait for
isPaused
. When you see the "Here" alert,isPaused
will befalse
already, andfirstFunction
will have returned. That's because you cannot "yield" from inside thefor
loop (// do something
), the loop may not be interrupted and will have to fully complete first (more details: Javascript thread-handling and race-conditions).That said, you still can make the code flow inside
firstFunction
to be asynchronous and use either callback or promise to notify the caller. You'd have to give up uponfor
loop and simulate it withif
instead (JSFiddle):On a side note, JavaScript 1.7 has introduced
yield
keyword as a part of generators. That will allow to "punch" asynchronous holes in otherwise synchronous JavaScript code flow (more details and an example). However, the browser support for generators is currently limited to Firefox and Chrome, AFAIK.An elegant way of waiting for one function to complete first is to use Promises with async/await function .
Quick example:
Firstly, create a Promise. The function above will be completed after 2s. I used
setTimeout
in order to demonstrate the situation where the instructions would take some time to execute (based on your example).For the second function, you can use async/await function where you will await for the first function to complete before proceeding with the instructions.
Note: You could simply resolve the Promise without any value like so
resolve()
. In my example, I resolved the Promise with the value ofy
that I can then use in the second function.Hope it helps for people who still visit this thread.