Javascript wait for function to finish - javascript

I know this question has been asked tens if not hundreds of times, but I turned google purple and still can't find an answer that suits my case.
I have a set of three functions that I need to call one from within the other, and need each function to finish before the one that calls it continues. Currently what happens is that a function would call another one, and then continue before the function it called finished.
Most of what I have seen says to use callback functions, my problem is that my inner most function is taken from a library, thus I can not adapt it to accept a callback function as a parameter. I also saw things on timeouts, but I do not want to force my code to wait any longer than it has to, I just want it to continue once the function it calls finished.
I just want everything to work synchronously, like I am used to from any other language.
To illustrate my current code, I am using three.js and this is (basically) what I have:
firstfunction(){
secondFunction();
}
secondFunction(){
var loader = new THREE.JSONLoader(); //loader is an object from three.js library
//loader.load is a three.js function that calls thirdFunction that I made. I can not make loader.load send a callback function to thirdFunction, as thirdFunction takes its arguments from three.js library
loader.load(url, thirdFunction);
}
thirdFunction(){ //this is a function that gets called from loader.load
//do stuff
}
I feel like I am missing something very trivial, but as I said I can't find anything online that fits my needs.
Any help would be greatly appreciated

Even if some libraries and apis allow you to do things synchronously, this is not how javascript should work. Even if you're used to this in other languages, javascript is different.
The answer to your question probably is 'this is not possible'.
Try to lean javascript the correct way, instead of making it behave like other languages.
However, there's some hope. Once you understand fully how callback works, and structure your code around that, you might realize that Promises is a better pattern that callbacks. Promises still need a sort of call-back and are still asynchronous, but it's easier to make your code easier to read.
Then once you fully understand promises, you might be able to use async and await. New browsers support this. These 2 keywords make a lot of your code 'look' synchronous like you're used to, but it's still asynchronous. It's pretty great.
Edit
I wanna address the follow sentence more directly:
//loader.load is a three.js function that calls thirdFunction that I made. I can not make loader.load send a callback function to thirdFunction, as thirdFunction takes its arguments from three.js library
Do you really need to send that third function another callback? What kind of callback is this? Is it just another function it should always call?
You can just call another function normally from your ThirdFunction. If you need it to be variable, you can probably just assign that function to a variable. Functions can access variables from their parent scope. For example:
var callback = '..'; // assuming this a callback.
thirdFunction(){
callback();
}
If only your second function knows what the callback should be, you might need to structure it like this:
secondFunction(){
var loader = new THREE.JSONLoader(); //loader is an object from three.js library
var callback = '...';
loader.load(url, function() {
thirdFunction(callback);
});
}

Related

How do I create a Javascript function call list that waits for the previous function to finish before calling the next?

I am currently building a signboard system that displays timetable information in a consistent format for various locations.
The idea is that each location has its own lightweight page with a small amount of variables that define the location specific parameters and then call the appropriate functions, in order, from a single external .js file.
My page is working fine with functions explicitly chained together, like so:
function one (){
//do the thing
two();
}
function two (){
//do the next thing
three();
}
function three (){
//do the last thing
}
What I am trying to do is separate the functions so that I can call them from a list in each individual page which will let me substitute different versions of certain functions as required in the different locations. Something like this:
function callList(){
one();
//wait for one to finish
two();
//wait for two to finish
three();
}
I have spent a lot of time reading about asynchronous functions, callbacks, promises etc. but the solutions that have been offered still seem to deal more with chaining functions together explicitly and passing a single variable as proof the function has finished, such as this (well written) example:
https://flaviocopes.com/javascript-async-await/
Part of my difficulty in figuring out the right solution is that my functions are quite varied in their purpose. Many of my functions don't produce variables at all and the ones that do (with the exception of a single ajax call) produce large sets of global parameters that don't need to be explicitly passed to the next function. Most, in fact, focus on rendering and manipulating svg and text in various ways, and due to the nature of the data displayed many rely heavily on loops.
As with most javascript problems I encounter I am sure that it is merely a gap in my understanding, but I feel like I am just reading the same articles over and over again and getting nowhere. I really need someone more knowledgeable to give me a nudge in the right direction.
Thanks.
Functions are first-class citizens in Javascript, so you can just throw them into an array and then loop through and call them.
var functionsToCall = [
one,
two,
three
];
// Call them (use your looping method of choice)
for (var i = 0; i < functionsToCall.Length; i++) {
functionsToCall[i]();
}
If your functions are synchronous and are not returning anything that you need, that's basically all you need. If your functions are async, then you might need something more like await functionsToCall[i](); or a setup using promises/callbacks instead.
If you need callbacks to tell you when a function has completed, you can use a small state manager/function to handle that (or you can use async/awaits if your environment will support them - they're cleaner to write! :) ).
Something like...
// A sample async function - you pass the callback to it.
function one(callback) {
// Do some async work, like AJAX...
// Let the callback know when I'm finished (whether I have a value to return or not.
callback();
}
// Simple state management - wrap these up with nicer code and handle errors and whatnot.
var funcIndex = 0;
function callNext() {
if (funcIndex < functionsToCall.Length) {
functionsToCall[funcIndex](callNext);
funcIndex += 1;
}
}
// To start things off:
function callAllFunctions() {
funcIndex = 0;
callNext();
}
If you need to have more granular control over the function calling, you can put custom objects into the array instead of just the functions themselves and change the behavior based on that.
For example:
var functionsToCall = [
{ func: one, isAsync: true },
{ func: two, isAsync: false }
];
Anyway, just some possibilities. It will really depend on exactly what you need for your particular situation!
use await
or
use promises
or
you need function1 execution complete handler will execute next one

chaining javascript functions

I searched this topic on SO for more than an hour and could not find a case like mine.
I have a web app that I developed on Ruby on Rails. It is based on a form with multiple fields and buttons to execute actions.
These are examples (my real app uses more functions and more combinations of actions):
When Field1 is changed, I want to execute JS functions function1(), then function2(), then function3().
When Field2 is changed, I want to execute JS functions function2(), then function3().
When Field3 is changed, I want to execute JS function function3().
All these JS functions call specific actions defined in my controller, and they update the form using AJAX. I'd like function2() to start executing only after function1() has finished updating the form, otherwise the results will be wrong.
Because controller methods that are called by these functions send API calls to many other websites, like Google geocode or Google timezone, their response time is unpredictable, and could be anywhere from a few 100's of ms to a few seconds.
I tried this:
onchange="function1();function2();function3()"
but that did not work because function2() started executing before function1() has finished the updates via AJAX, and the same issue for function3() with regard to function2().
I also tried:
onchange="function1();setTimeout(function(){function2();setTimeout(function(){function3()},FUNCTION2_DELAY)},FUNCTION1_DELAY)"
but that did not work either because if FUNCTION1_DELAY is set too long, function2() will not start executing before FUNCTION1_DELAY has expired, whereas function1() might execute much faster than FUNCTION1_DELAY, and if FUNCTION1_DELAY is set too short, function2() will start executing before function1() has finished the updates that are needed for function2() to run. The same thing for function3() with regard to function2().
My question is : is there a smarter way to make function2() start executing only when function1() has finished updating the form via AJAX, and the same for function3() with regard to function2()?
I know I could create new controller methods where I merge these functions, like merging function1(), function2() and function3() into new_function1(), ..., etc., but that makes my code contain repetitive actions and will ultimately make it harder to maintain. So I'd rather look for a smarter way to handle this issue.
you need to use Promises.
Basically it works like that:
var MyFunction1 = new Promise(
function() {
//do stuff here
}
);
MyFunction1.then(Myfunction2 ...).then(Myfunction3 ...;
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
http://api.jquery.com/promise/
setTimeout is asynchronous, so that won't work. You could call function 2 at the end of function 1, but still inside the function. Similarly for function 3:
function one(){
...logic...
function two();
}
function two(){
...logic...
function three();
}
function three(){
...logic...
}
Alternatively, you could create some sort of queue of functions, and only move to the next when the current one is finished:
var functionQueue = [
one,
two,
three
];
function next(){
var nextFn = functionQueue.shift();
if( nextFn ){
nextFn();
}
}
function one(){
...logic...
next();
}
// same for two & three
You can also use promises, which are quite powerful and make the code clearer to read, but may be overkill for this problem

Are All Node "callback" Functions Potentially Asynchronous?

I'm a (relative) node newbie getting in the system, and all the enthusiasm in the community for "just write callbacks, everything's asynchronous and event driven, don't worry!" has left me a little confused as to the control flow within a single program (or in more node-ish terms, the control flow during the handling of a single request in a larger program)
If I have the following program running under node
var foo = function(){
console.log("Called Foo");
};
var bar = function(){
console.log("Called Bar");
};
var doTheThing = function(arg1, callback){
callback();
};
doTheThing(true, function() {
foo();
});
bar();
Is there any chance that foo will execute after bar? When I run the program via the command line locally, it's always
Called Foo
Called Bar
but I see so many warnings from well intended evangelists along the lines of don't assume your callback will be called when you think it will, that I'm unclear if they're just warning me about library implementation details, or if node.js does something weird/special when you use a function object as parameter.
No, there's no chance. Not for that code.
If you're writing your own functions, or if you have access to the code, you don't need to assume, you know whether everything's synchronous or otherwise, but if you don't have access to the code, or haven't yet read it, then no, you can't assume callbacks are going to be synchronous.
It's however bad practice to make assumptions like that for two reasons, first is that just because it's synchronous now doesn't mean somebody else, or forgetful future you can't change it later, and secondly, because if it's all synchronous, why are you/they using callbacks in the first place? The entire point of callbacks is to allow for the possibility of asynchronous calls. Using callbacks and then acting like they're always going to be synchronous, even if you know that's the case, makes your code confusing for anybody else coming in.
No
Your sample code is 100% synchronous, single-threaded, simple top-to-bottom. But that's because you don't do any I/O, don't have any real asynchronous calls, and don't use process.nextTick, setTimeout, or setInterval. To more realistically simulate async calls do something like:
function fakeAsync(name, callback) {
setTimeout(function () {
callback(null, name);
}, Math.random() * 5000);
}
function logIt(error, result) {
console.log(result);
}
fakeAsync('one', logIt);
fakeAsync('two', logIt);
fakeAsync('three', logIt);
Run that a few times and you'll see out-of-order results sometimes.
Is there any chance that foo will execute after bar?
In your current code, no. Although your doTheThing function has an asynchronous function signature (i.e. it takes a callback as the last argument, which to an outsider with no knowledge about the function's implementation would suggest that it's asynchronous), it's actually fully synchronous, and callback will be called without yielding to the runtime.
However
You really have no reason to give your doTheThing code an asynchronous signature, unless you're accommodating for introducing real async behavior into doTheThing at some point. And at that point, you have a problem, because the order in which foo and bar are called will flip.
In my opinion, there are only two good ways of writing code like you do: Either make it set in stone that doTheThing will be synchronous (most importantly: that it won't be dependent on I/O), which means that you can simply return from the function:
doTheThing = function(arg1){
return null
};
doTheThing()
foo()
bar()
or change the stub implementation of doTheThing directly to include a call to setImmediate, i.e.
var doTheThing = function(arg1, callback){
setImmediate(function() { callback(); );
};
Note that this can also be written as
var doTheThing = function(arg1, callback){
setImmediate(callback);
};
but that's just because at this moment, callback does not take any arguments. The first version is more close to what you had.
As soon as you do this, bar will always be called before foo, and it has now become safe to introduce async functionality into doTheThing.

Implement a callback with a function that doesn't accept a callback?

This is a newbie question: I have a pre-existing function that I would like to have call another function when it is finished, however, it does not accept a callback nor of course call one. I can modify this code to accept and call a function however this got me thinking about whether JavaScript supports doing this ... I would think it does but I've never had reason to find this out, I'm assuming it's necessary when working with libraries where we cannot change the code to our liking. Thanks.
The only time you need a callback is when you are doing something asynchronous, such as:
making an HTTP request (and waiting for a response)
animating something, one frame every time period until it is done
waiting for the user to click a button
All of these are considered "done" when something happens, but there is no generic way to determine when the something has happened. You need something custom for each one.
If you aren't waiting for something, then you can just call one function after the other (foo();bar();) and not need to fiddle around with callbacks.
So…
It might be possible to do what you want, but we can't tell you a generic way to achieve it.
This is a bit of a hack, and i'm sure there's tidier ways to do this with polymorphism, but you can treat the function as a variable and re-assign it somewhat:
Say you start with this function:
function originalFunctionName()
{
// do something
}
you can assign the existing function to a new name:
var backupOfOriginal = originalFunction;
then you can define a new function over the original name:
var originalFunctionName = function()
{
// do something else
// call backup function
backupOfOriginal();
}
then if you call the original function name:
originalFunctionName();
all the code will execute.
You can always create a new function which calls that function and provides you with opportunities to do something else before and after it is called. Underscore.js provides .wrap() to do exactly that sort of thing and return you a function you can call instead of the first function.
That just gives you a new function to call instead of your original function, if you want every spot that called the original function to get the new behavior instead, you could take advantage of JavaScript's prototypal inheritance to replace the original function with your new version of it.
Create a wrapper function that calls the original function, then one you pass in.
If the original function is an Ajax call and you're trying to replace one of its handlers, that's a different issue, though you might be able to use jQuery's $.when(original).then(function () { ... }) depending on your actual needs.

slow down code until ajax function is over?

I want to call fillContent then later called beginEditingQuestion
fillContent(cid, "questions");
beginEditingQuestion(qid);
The problem is that I can't rung beginEfitingQuestion until all the ajax in fillContent is done. Is there an elegant way to delay the code? The only idea I can think of is to make a totally new function fillContentAndBeginEditingQuestion where I copy and paste fillContent into the new function and in the final ajax call add in beginEditingQuestion. This doesn't seem very elegant to me, I want to reuse fillContent in other contexts. What should I do?
You can make fillContent take a callback parameter, and have it call the callback when it's done. Basically, you'd just add callback (); into the body of fillContent at the very end. In this way, you'd write something like this, and have the passed function executed at the end:
fillContent (cid, "questions", function () { beginEditingQuestion (qid); });
I don't think you want to "slow", rather you want to wait for something to complete before the next piece of work is begun.
A pattern for this, used in many languages, is to use Events.
Conceptually:
You register an interest in a "DoneFillingContent" event, saying please call beginEditingQueue() when the event arrives.
fillContent has the repsonsibility of emiting an event to all interested parties. He doesn't realise what beginEditingQueue() does, it just a piece of work to be done on completion.
In the simplest version of the pattern, you just allow one callback function.
It sounds like you need to change "fillContent" so that one of its parameters is a callback function that is invoked when the AJAX returns.

Categories

Resources