I have two javascript functions
function one () {
do something long... like writing jpgfile on disk
}
function two () {
do something fast... like show the file
}
I call it (in jQuery) like this
one ();
two ();
Because function two needs the link file from function one, i need to be sure the execution is completed... so getting the function two in the callback of function one should be the trick.. but how to do that ?
note : I did put an alert ('aaa') between those two functions to let function one complete, and it worked fine... when the alert is commented (removed) nothing works anymore !
You only need to use a callback if you are doing something asynchronous, otherwise it doesn't matter how long something takes, the next function won't run until the first has finished.
A callback is just passing a function as an argument, and then calling it when done.
function one (callback) {
do something long... like writing jpgfile on disk
callback();
}
function two () {
do something fast... like show the file
}
one(two);
Obviously, if you are doing something asynchronous, then you need something that will tell you when it is finished (such as an event firing).
Simple:
function one (callback) {
do something long... like writing jpgfile on disk
if(callback) callback();
}
function two () {
do something fast... like show the file
}
one(two);
Try this,
$.when($.ajax(fuction1())).then(function () {
fuction2;
});
Here fuction1 is your first function to call, and fuction2 is your second function.
I think it's easy if the browser wait for the process inside "one()" to be done before execute the next line of command. The iceberg hit titanic cause it doesn't wait. Then executing this:
one(two) // while two is the callBack parameter
is nothing different from:
one()
two()
I suggest using a setInterval.
function one(){
//--- Write the file to disk
//.....................
}
function runTwo(){
if (check_the_written_file_existence){
clearInterval(t)
two();
}
}
var t = setInterval("runTwo()",500)
The most important point is that if there's an event fires when the "long process" in function "one()" has done, you just need to bind function two to that event. Unless, you must check the result by someway every span of time until it's really done.
Related
In this article which I was referred to the following statement is made:
Callbacks are a way to make sure certain code doesn’t execute until other code has already finished execution.
The article then goes on to illustrate this with an example:
function doHomework(subject, callback) {
alert(`Starting my ${subject} homework.`);
callback();
}
doHomework('math', function() {
alert('Finished my homework');
After this the articles states:
As you’ll see, if you type the above code into your console you will get two alerts back to back: Your ‘starting homework’ alert, followed by your ‘finished homework’ alert.
The implication seems to be that by using a callback the desired order of code execution has been ensured. That is you start your homework before you finish it. However, I feel I may have misunderstood the whole point of the article and therefore still do not understand callbacks and asynchronous code because when I slow down the first part of the doHomework function using setTimeout() the code executes (or at least returns) in the opposite order:
function doHomework(subject, callback) {
setTimeout(function(){
console.log(`Starting my ${subject} homework.`);
}, 500);
callback();
}
doHomework('math', function() {
console.log('Finished my homework');
});
The result I get from that is:
steve#Dell ~/my-app $ node app.js
Finished my homework
Starting my math homework.
});
I am using node here (hence console.log() replaces alert()) but I do not think that is relevant.
It seems to me I have missed something quite fundamental and need to try and access what it is that I am trying to understand before I then try and understand it.
Any assistance on this journey would be greatly appreciated.
After getting great feedback I think the homework analogy was not helpful so I am now using the first code example in the article I referenced. The article gives this code:
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
The above returns 2 then 1 in the console.
I tried (without success) to reverse the return order to 1 then 2 with this:
function first(callback){
setTimeout(function(){
console.log(1);
}, 500);
callback();
}
function second(){
console.log(2);
}
first(second);
The answer I got from Cleared (before it was edited) was to put the callback() inside the setTimeout() function. He used the homework example but here it is with this example:
function first(callback){
setTimeout(function(){
console.log(1);
callback();
}, 500);
}
function second(){
console.log(2);
}
first(second);
I think that is closer to what I am imagining the article was getting at. It seems to make sense although I guess the precise context of what you are doing and what you want to happen determine what is right or wrong.
In general, the call to the callback is not at the end of the function, but rather after you have done the important things.
So if I understand your question, the doHomework-function should start doing homework (which takes time, in this case 500ms), and then the homework is finished. So the important things in your case is the console.log('Starting my ${subject} homework.'); which "takes 500ms" (since this is the time you need to do the homework).
Therefore, you should put the call to the callback right after console.log('Starting my ${subject} homework.');, i.e.
function doHomework(subject, callback) {
setTimeout(function(){
console.log(`Starting my ${subject} homework.`);
callback();
}, 500);
}
doHomework('math', function() {
console.log('Finished my homework');
});
Generally, you would call the callback function when you are finished doing whatever it is you are doing.
So you have the code inside and outside your setTimeout function backwards.
function doHomework(subject, callback) {
console.log(`Starting my ${subject} homework.`);
setTimeout(function(){
console.log(`Finished my ${subject} homework.`);
callback();
}, 500);
}
What exactly is callback?
Callback meaning function-in-function like recursive.
Let me give you an example:
Every day we eating then sleeping. But in JS code, JS is an impatient language unlike PHP. This is the example code:
// Consuming 3s to eating(just an example, not really 3s)
function eating() {
setTimeout(function() {
console.log('Eating...');
}, 3000);
}
// Then go to sleep
function sleep() {
console.log('Z..Z..Z');
}
eating();
sleep();
But you sleep immediately after...(When we run the code it runs the sleep first then eating())
To assure that everything works in order, meaning you only go to bed when done eating. So we need the eating() to tell when it's done to start the sleep():
// Consuming 3s to eating(just an example, not really 3s)
function eating(callback) {
setTimeout(function() {
console.log('Eating...');
callback() // the function which will be proceeded after "Eating..."
}, 3000);
}
// Then go to sleep
function sleep() {
console.log('Z..Z..Z');
}
// call the function
eating(function() {
sleep();
});
Yeah! Right now I think you can use callback in your code!
Where you can see callback?
You can see it in every JQuery code:
$("#hide").click(function(){ //the click() function call the function inside it which is callback
$("p").hide();
});
$("#show").click(function(){
$("p").show();
});
Callbacks in Javascript are used in asynchronous programming, where you can't ensure that the code above is running before the code below, like loading files from a server asyncronous.
The problem is, that with normal sequential programming, you can not ensure, that the data you fetch is fully loaded when the programm is running (i.e. if you run the script, one time the variable could be setted, another time it could be undefined, cause async task is still running), so you set a callback function, which gets connected to different states, ie. success or error on ajax call. The difference to normal programming flow is, your programm does not stop till it has loaded the data (or in your case, the timeout doesnt pause your program, the code afterwards is computed and the timeout can run of anytime, if you dont use a fix value).
So, to ensure that your code will run when the needed logic finishes, you have to pass a callback function, which is executed when the needed state is fulfilled (i.e. success/error on loading tasks, or a timeout is "finished".
The homework example IMO isnt the best sample, cause it doesnt touch the real use cases, as it always "waits" 500ms.
In your example the problem is, your "callback" is out of the "asyncronous" part of code, so its executed directly after starting the timeout, even if the timeout still is "running". Maybe your thinking of SetTimeout is the problem, in my javascript beginnings I thought its more like "pause for 500ms", but its "execute the scoped code after waiting for 500ms out of the normal code flow"
Here are some more informations, I can recommend the whole page, even if your not javascript noob ;)
https://javascript.info/callbacks
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 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
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');
}
}
$('#div1').focus(function () {
callAnotherFunction();
$(this).animate({});
}
I'm trying to make $(this).animate({}); execute after callAnotherFunction(); has completed. Currently, both run at the same time. I've timed to use delay(), setTimeout() to no avail too. Is there anyway this can be done?
Thanks!
JavaScript is single threaded, so only one expression will be executed at a time. In the example that you've given, $(this).animate({}); will not run until callAnotherFunction(); has completed.
It's possible that callAnotherFunction(); runs additional code on a timer or delay, in which case you would have to have $(this).animate({}); on a timeout with an equal or greater delay for it to execute afterwards.
When in doubt, pass your function as a parameter:
$('#div1').focus(function () {
var $t = $(this);
callAnotherFunction(function(){ $t.animate(); });
}
... with callAnotherFunction looking something like this:
function callAnotherFunction(callback){
// do whatever you were previously doing, and then...
callback();
}