I recreated this example (from link given below) to understand callbacks. The problem is that the callback gets executed before the parent function 'first()' finishes. setTimeout works fine but callback doesn't wait until after the above . If i comment out line 1 and 3 of first() i.e. the timeout part, then it logs in the right order.
<script type="text/javascript">
function second() {
console.log("second/callback function")
}
function first(callback){
setTimeout(function(){
console.log("first function")
}, 1000 );
callback();
}
first(second);
If this is working fine and i misunderstand the nature of setTimeout, then please give another example where the callback can be seen waiting.
Link:
https://codeburst.io/javascript-what-the-heck-is-a-callback-aba4da2deced
Note: I know very little JS, was actually working in PHP, so kindly give a simple explanation. Thanks
It appears that you misunderstand how setTimeout() works. This tool called Loupe by Philip Roberts may help you understand. I've taken your code placed it into the tool which will allow you to visualise what is actually happening - link to Loupe
When you use setTimeout, that function provided as the first parameter is delayed for the number of milliseconds provided in the second parameter (in your example, this is 1000). The rest of your code will continue to execute in order until this timeout has lapsed.
If you want your callback function to execute after the given timeout: you can actually just write it such like:
setTimeout(callback, 1000) <- Since callback is already a function, you don't need to wrap it in another function unless you wish to do other operations before calling the callback.
Update 1 (2018-10-26):
function second() {
console.log("second/callback function")
}
function first(callback){
console.log("first function")
setTimeout(callback, 1000);
}
first(second);
Here you are calling "callback" synchronously which means first function will wait for second(callback) function to be completed and then proceed with it's execution. To understand it better I have put console log at other places as well. Pls try below and see if you now have better understanding for the same
function second() {
console.log('second method started')
setTimeout(() => console.log("second function executed"), 1000)
console.log('second method finished')
}
function first(callback){
console.log('first method started')
setTimeout(() => console.log("first function executed"), 1000 );
callback();
console.log('first method finished')
}
first(second);
Related
I am trying to wrap my head around callbacks and I do not understand how callbacks guarantee that a statement will execute after(in terms of time) another statement which takes an unknown amount of time. I do not care about promises,await,async, etc but just plain callbacks as I am trying to learn.
For example below, my method will execute the callback before the unknown time event has occured. I can see how callbacks can be used to execute something because an event occurred but not how they can be used to guarantee that something will be executed after(in terms of time) something else has finished executing and returned something meaningful.
function foo(callback) {
setTimeout(() => console.log("Do something with unknown time"),
2000);
callback();
}
function callback() {
console.log("Execute callback");
}
foo(callback);
So what I am asking is can callbacks be used to guarantee execution sequence in the time domain ? Or is their only purpose responding to events ?
Callbacks is a way of invoking a function that is passed as a parameter to invoker function(in your example foo). Callbacks guarantee that a function will be invoked if no error occurs before it's call inside the function. Callbacks aren't asynchronous either but the way it executes later inside the function after some line of code makes everyone think it as asynchonous at first.
And as you've added setTimeout function on the above example, setTimeout is an asynchronous callback envoker function that calls it's callback(in your code () => console.log("Do something with unknown time")) asynchronously after a certain defined time(2000). So, setTimeout wont stop the execution for 2 seconds as you've expected, instead it let's the further line of codes execute without worrying about what will happen inside it's callback. So, the callback() will trigger at that instant when foo(callback); is triggered.
You can find more info about callback in here.
You have asked two questions,
Is callback execution sequence guaranteed?
Is callback only respond to events ?
Answer
Yes.
From my understanding, callback is just calling another function to be run now (when it is called)
It is guarantee to run immediately when you call it.
To ensure something is called before the callback is triggered, simply put the things you want to call execute first before callback is conducted.
e.g. from your code, by modify it a bit, callback is guarantee to run after the console.log is executed.
function foo(callback) {
setTimeout(() => {
console.log("Do something with unknown time");
callback();
}, 2000);
}
function callback() {
console.log("Execute callback");
}
foo(callback);
It is the setTimeout which defers the execution, and is not related to callback methodology.
Sure, callback can be used as a callback to respond to event, just like elem.addEventListener("click", callback);. But not only that.
A simple example will be illustrated below.
e.g.
var map = function(arr, callback) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
result.push(callback(arr[i]));
}
return result;
};
map([0, 1, 2, 3], function(item) {
return item * 2;
})
Edited
This edit is referring to
For example, if I am making a database call, I do not know how much time it is going to take for the data to be retrieved. If i try to access it before it has arrived, I'll get an error.
Calling a database, is by no means different from an async http request. So here, I will use XMLHttpRequest to demonstrate how to use callback to ensure this. But normally, these are features provided in browser or node.js already. So you do not need to write it by your own. Of course, to prevent callback hell, I will personally prefer use of Promise or async/await. But this is a bit out of topic.
So let see how XMLHttpRequest can use callback to handle async task.
var sendRequest = function(callback) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback(this);
}
};
xhttp.open("GET", "filename", true);
xhttp.send();
}
and you can use callback to handle async event. Sometime you dont know when it will happen. And the basic idea how it works is from the example I have said in answer 1.
If I understand you mean correctly, you can use callback as an event to do something, such as: onerror, oncomplete...
In this example, we start to run todo function, and we have oncomplete function which can be used as callback to do something after completing works on todo function.
While running, if there is some error, it will be logged to onerror function.
function todo(oncomplete, onerror) {
try {
console.log("Start...");
console.log("Do something with unknown time");
setTimeout(() => oncomplete(),2000);
// you can try to throw error here to test
// throw new Error("Some error message...");
} catch (e) {
onerror(e);
}
}
function oncomplete() {
console.log("Done!");
}
function onerror(e) {
console.error(e.message);
}
todo(oncomplete, onerror);
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 am a bit confused about setTimeout.I want to confirm whether the output for the following code will always be:
inside abc
inside sample
The code:
function abc() {
xyz();
// interactions and modifications in DOM
$("#id1").append("something");
$("#id2").val("set something");
$("#id3").after("create some dynamic element");
// 10 to 20 interaction more...
console.log('inside abc');
}
function xyz() {
setTimeout(function() {
sample();
},0);
}
function sample() {
console.log('inside sample')
}
It would be great,if somebody could explain the whole flow with the call stack.
Yes, it will always have that output.
The callback inside a setTimeout will not be called until the execution context is clear - i.e. the currently executing sequence of code has finished.
This means that even if you do
setTimeout(function () { console.log("1 second!"); }, 1000);
var start = +new Date();
while ((+new Date()) - start < 5000) {}
1 second! will not be logged any sooner than 5 seconds have passed.
setTimeout() will run asynchronously after finishing current execution block. So output should be same always:
inside abc
inside sample
Javascript internally manage an event queues internally for all async tasks. Every time it checks its async queue after finishing current execution block.
Yes, the console output will always be the same. setTimeout's callback function is executed asynchronously after the context that called it is cleared. When setTimeout is called, it places its callback function on the stack and returns to the current execution context. When that is done (in your example, when abc is fully executed), the callback function is executed, which in your example basically calls sample immediately. So your code output will never be different.
The fact that setTimeout's callbacks are themselves executed asynchronously can be seen if you placed a longer setTimeout function somewhere inside abc before calling xyz:
function abc() {
setTimeout(function(){
console.log('wait')
},1000);
xyz();
console.log('inside abc');
}
function xyz() {
setTimeout(function(){
sample();
} ,0);
}
function sample() {
console.log('inside sample');
}
abc();
...your console will log:
inside abc
inside sample
wait
To hold sample's execution until the longer timeout is complete you would need to place the setTimeout calling sample inside the longer setTimeout.
If setTimeout's callback is ever behaving differently, it's most likely due to being accidentally passed a function call instead of a function pointer, like this:
setTimeout(sample(),0);
instead of
setTimeout(sample,0)
Also, just in case you didn't know (or for others), you can add
debugger;
at any point(s) in your Javascript code and then run the code to view the callstack at that point using dev tools (in Chrome it is in the right panel under 'Sources').
I'm trying to make a removeClass function work right after another function ends, so I have this script to call a fittocontainer:
function fittocontainer(){
$('.fittocontainer').fittocontainer()
}
And I want that after the function 'fittocontainer' ends, apply this function:
setTimeout ( function(){
$('#footer').removeClass("active");
})
How can I integrate the setTimeout function with the 'fittocontainer()' to work after it has just ended?
Is fittocontainer a function that you made? If so, and it is asynchronous, you will have to add a callback like:
function fittocontainer (cb) {
//do some stuff
cb();
}
Then you can call it passing a function or even an anonymous function like:
fittocontainer(function () {
// do stuff afterwards
});
If this function is updating the DOM it is most likely asynchronous. Using a timeout to try and execute code after an async method is very dangerous and should never be done.
If it is synchronous, you can simply call a function on the next line and know that it will execute after fittocontainer is complete.
Also remember that you need a timeout on the setTimeout like:
setTimeout(function(){
$('#footer').removeClass("active");
}, 1000);
that is a timeout of 1 second
setTimeout() is about time (minutes, seconds), if you only want to execute that function at the end, you could just call it, or you could use a callback function:
function fittocontainer(callback){
$('.fittocontainer').fittocontainer();
callback();
}
and then call fittocontainer:
fittocontainer(function(){
$('#footer').removeClass("active");
});
I am confused about the example in http://dreamerslab.com/blog/en/javascript-callbacks/
function do_a(){
// simulate a time consuming function
setTimeout( function(){
console.log( '`do_a`: this takes longer than `do_b`' );
}, 1000 );
}
function do_b(){
console.log( '`do_b`: this is supposed to come out after `do_a` but it comes out before `do_a`' );
}
do_a();
do_b();
results
`do_b`: this is supposed to come out after `do_a` but it comes out before `do_a`
`do_a`: this takes longer than `do_b`
and the author's explanation is "However javascript is an event driven language. If do_a takes longer than do_b, the result of do_b comes out first than do_a;". I am still not quite clear, please explain in details, or please point me to some specific material, thank you,
setTimeout says to execute its function after 1 second. Each function returns immediately, while setTimeout executes after that time.
In actuality, do_a() and do_b() are executing in order. But the results of setTimeout are independent of do_a or do_b.
Further, that is a poor example of callback function execution since setTimeout has nothing to do with a callback. A better example is as follows:
var a = function(callback){
setTimeout(function(){
callback();
}, 1000);
console.log('1');
}
var b = function(callback){
setTimeout(function(){
callback();
}, 2000);
console.log('2');
}
a(function(){
console.log('3');
});
b(function(){
console.log('4');
});
do_a() and do_b() are executed immediately one after the other. When do_a() executes, it starts a timer which prints the output in 1000ms (after the output of do_b() has been printed)
So they do execute in order, it just doesnt wait for a response