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.
Related
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
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);
});
}
I have three functions that all work with data from a global object. This global object gets filled with data from a local array in one function and with data from an ajax request with the second function. The third function relies on the data in the object, so the ajax request must have been completed.
I believe I am misunderstanding callbacks. Here's what I do:
var currentCharacter = {}
// this function gets the local data and then calls the second function
function loadData(getMarvelData) {
// do things to fill currentCharacter
getMarvelData(); // this is the callback to the next function (no ?)
}
// this function performs the ajax request, then calls the third function
function getMarvelData(getGoogleMap) {
// do ajax request and add stuff to currentCharacter
getGoogleMap(); // this is the callback to the final function (no ?)
}
function getGoogleMap() {
// do Google Map related stuff with data from currentCharacter
}
I thought setting a function as an argument of another function and then executing it would make the function dependent on the other before it continues. Clearly I still misunderstand callbacks after trying to make it work for a week now. As it is, the getMarvelData function doesn't even get called because I never see the alert popup and the currentCharacter object only has data from the loadData function.
Could somebody show the correct approach for my code, or if my approach of making these three functions is even the right one for this scenario.
The full repository is available at: https://github.com/ChaMbuna/Marvel-Map
V0.9 was actually working but the ajax call was set to run synchronous (it still is btw) Since then I've been overhauling my code to make it work asynchronously and to remove all jQuery (this is a Udacity project and removing jQuery was suggested by an instructor).
Appreciate the help
I have not enough reputation to put a comment, but a wild guess, you should remove the argument in loadData&getMarvelData or actually pass a function in calls to those function.
You have to pass the parameters correctly.
Try this:
var currentCharacter = {}
loadData(getMarvelData, getGoogleMap);
function loadData(f1, f2) {
// do sth.
f1(f2);
}
function getMarvelData(f2) {
// do sth.
f2();
}
function getGoogleMap() {
// do sth.
}
I havn't tested it, but it should work.
I have to call two functions on form submit but i want to make sure that that second function is executed only after the first function is executed.
I do not have control over the first function, so i cannot edit it at all.
function a(et){
//function a script
}
function b(evt){
//function b script
}
from function b is there a way that i can check if function a was completed or executed fully.
if you have no access to a at all then you can't do what you want to do here. No way: JS creates a call object when a function is called, and auto-GC's it when the call is complete. Sadly, the actual mem-management is off limits, so you can't check that. other trickery involves your meddling with the code of function a, which you say you cant get at... so no, you can't do this.
Sorry for that, but it's as the FAQ says: you might not always get the answer you're hoping for, but that doesn't mean the answer you don't like isn't true... :-P
There is, however, a little bit of hope for you: if both function a and b are callbacks or handlers of a submit event, you could look into ways of queueing those calls. Given the jQuery tag .queue() suggests itself
According to Eli Grey you can tested like this:
function foo() {
foo.complete = false;
// your code here
foo.complete = true;
}
foo.complete = false;
if (foo.complete) { // foo execution complete
// your code here
}
Yes, you can, there is a lot of ways to do that, but here is a simple way to make it.
You can use persistent object localStorage.
You can use session object sessionStorage.
function a(evt){
// Asynchronous function
// ... your code here
// before finish function create the persistent object
localStorage.setItem('myObject', 'done');
return;
}
function b(evt){
// Checks if a() function was completed
var _done = localStorage.getItem('myObject');
if(_done && _done == 'done') {
// your code here: the a() function was completed
localStorage.removeItem('myObject');
}
}
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.