Understanding callback function

Hi,
1- so far i learned that javascript executes code sequentially—

function one(){
console.log("1");
}
function two(){
console.log("2");
}

one();
two();

output:1
2

2- if there is some delay in execution of one function then it will execute next one( server request etc)

function one(){
setTimeout(function(){
console.log("1");
},3000);
}

function two(){
console.log("2");
}
one();
two();

output:2
after three seconds–1
irrespective of function call

3-- to overcome this behaviour callbacks is used

function one(callback){
setTimeout(function show(){
console.log("one");
},3000)
callback();
}

function two(){
console.log("two");
}

one(two);

so as per definition one has to wait 3 seconds before it executes two

but output is completely different

output 2
1

it should be 1,2
why didnt it wait for one to complete before executing two
Kindly explain…
Thanks in advance

The output is

two
one

because you are putting a delay of 3 sec to execute function show(). The function one calls the callback function (which in this case is two()) immediately after the setTimeOut. So function show is delayed for 3 seconds, but the function one itself is executed without any delay.

i still confused , then what is the use of callback , what if there was server request in place of setTimeout

at that point you will need to deal with promises and async and await

yes! but then what callback used for ?

a callback is just a function given as argument to an other function

of course ,but for which purpose

By setting a timeout you’ve introduced asynchronous behaviour which is similar to what would happen if you replaced your timeout with a network call to a server like you mentioned in another reply.

The callback is simply being called when the timeout finishes or in the network call analogy, when the request returns a response.

JavaScript doesn’t “wait” like you’re assuming. It instead continues on and “callsback” the first function when it’s finished its asynchronous job (a network call or timeout).

To handle that you move the code that you don’t want executed until the execution of the callback inside of the callback. In your case that would mean placing your call to callback() inside of the other “callback” (the function you’re passing as an argument to setTimeout. It would look like this:

function one(callback){
  setTimeout(function show(){
    console.log("one");
    callback();
  },3000)

}

function two(){
console.log("two");
}

one(two);

The above example will print:

One
Two

If it helps you understand, your code has two callbacks not just one.

Either way, this is the classic way of dealing with asynchronous programming in JavaScript and what I assume you’ve been trying to learn about and understand.

I think it’s a good idea to get a handle on this, but it’s also worth knowing that most apps today don’t deal with asynchronous programming this way anymore.

In later versions of JS (ES6 and beyond) we were given Promises. They allow us to deal with asynchronous behaviour without passing around all these callback functions (known as “callback hell”). Promises is a whole other topic to learn so I won’t explain here but it’s necessary to learn about.

After you understand Promises, the next additions to JS was Generators and Yield. You don’t have to learn about that but it’s worth knowing that the new async/await syntax is built on top of what Generators and Yield allows us to do which is essentially pause the execution of code while we wait for an asynchronous function to finish it’s work so that our code “looks” like it’s synchronous (running each line one after the other).

And I’d say that most modern applications are being written with the async/await syntax these days so it’s pretty important to learn.

2 Likes

Hi, thanks a lot for explaining so wonderfully
i still have one question
what does this code says—

function one(callback){
setTimeout(function show(){
console.log(“one”);
},3000)
callback();
}
to me it is saying that show is taking 3 seconds but it is sort of server type of request so wait it for three seconds and then execute callback? am i right?

1 Like

show will be executed after 3 seconds, callback will be executed immediately

1 Like

yes, thanks a lot to you as well

Hi,
Just a couple of words more…
setTimeout is the first statement (you forgot the semicolon… It is not required for running but required for understand the code!)
... 3000);
callback() is the second statement. It will run after executed setTimeout imidiatly. It will not wait for 3000 ms, even not wait 0 ms.
Change your code from 3000 to 0 ms and try to understand what happend and why…

Don’t feel bad, this confuses a lot of people. Just remember that a callback is just a fancy word for a function, usually a function that is passed in as a parameter to another function. And remember that in JS, functions are just variables like any other, they are technically a type of object in JS.

perhaps this perspective will help:

function one(callback) {
  function show(){
    console.log("one");
  }

  setTimeout(show, 3000);

  callback();
}

So, three things happen in the function one.

  1. We define the function show.

  2. We call setTimeout. We tell it that we want it to run show after 3000ms.

  3. We call callback.

Now, callback will always get executed before show because JS will always get to that line much, much faster than 3000ms. Technically, you could say that setTimeout will get run before callback. That’s true, but you won’t see the effect of that for 3000ms. Everything is doing that it’s doing is behind the scenes. It is telling JS, “Take this function I give you as the first parameter, and wait however many milliseconds the second parameter tells you. Don’t wait for this, just put this function on the timer thread and when it is time, put it in the queue so it can be run.”

3 Likes

So I think you’ve gotten yourself confused by calling your callback function “callback”. It might make more sense if I rejig your example a bit:

function one(two){
  console.log("one")
  setTimeout(two, 3000)
}

function two(){
console.log("two");
}

one(two);

This will output One followed by Two 3 seconds later. If you move the console.log("one") line below the setTimeout line you’ll get the opposite effect.

Remember that setTimeout takes a function as it’s first argument. So you can just pass a function as if it were a variable like in my example above.

In the example, you call one with the argument two. one now console.logs “one” and then sets a 3 second timeout. When the timeout finishes (3 seconds has passed) it will then run the callback which I renamed to two to make it more clear.

In your original example, you were defining a new function as the argument to setTimeout which is where you had console.log("one") and then you had console.log("two") outside of the setTimeout argument’s function (the second callback in your example).

That’s why the behaviour you were seeing was that the output would be Two followed by One 3 seconds later.

I think you should note the example that @kevinSmith gave. It’s just a reformatted version of your code but instead of defining the show function inline like you had it’s pulled out into a variable which I think makes the code easier to read in this case.

1 Like

In normal execution environment, when you call a function, you wait until the function returns with an answer. Suppose I have this

let result = getDataFrom(localStorage);
display(result);
doMoreWork();

and let’s imagine the getDataFrom() function can take up to 5 seconds to return the result. This means that display won’t get executed for 5 seconds. And doMoreWork() won’t get called until display is completed. Without getting into nitty gritty, in a mobile app or web app environment, it basically means that the user interface becomes unresponsive while you wait for the result. So, what you want to do is, instead of waiting for the result to come back, to specify a function you want to get executed when the result is available. You do something like this

getDataFrom_2(localStorage, display);
doMoreWork();

This version of getDataFrom is called an asynchronous function and display a callback function. The system won’t wait for the function to complete, because it is asynchronous. doMoreWork() gets called immediately so you can continue with other work (like handling user interaction) without waiting. When geDataFrom2() gets done, it will call its callback function display and pass the result to it. Again, I’m avoiding details so we can focus on general concept.
As to the setTimeout function, the sample examples are using it to simulate a function that takes long time to complete. It has no direct relevance to something being asynchronous or callback.

1 Like

@twotani @kevinSmith @dannyjamesfletcher @lendoo @ilenia
Hi to all,
Thanks for such great explanation, if you could manage few more time, i found one json file from internet which can serve a purpose of server request.
address is https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json

can we use it as an example of callback without promise?
waiting for reply…

It’s not clear to me how this relates to the previous code discussed. There may be a situation where you might use a callback or promise with a json file (like if you fetch it). Can you show us what you’ve tried?

Hi, i tried two things but with promise(though i dont deeply understand promise)

1-Default javascript behaviour

function show(){
var data="https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json";
fetch(data).then(function(file){
console.log(file);
});
console.log("s");
}

show();
output:   s
                    file

2- changing default behavior via callback

function show(callback){
var data="https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json";
fetch(data).then(function(file){
console.log(file);
});
callback();
}


function show2(){
console.log("s");
}
show(show2);
output:   s
                    file

both output is same???

I’ve edited your post for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (’).

Right, those both accomplish the same thing in different ways. If you by 3 cartons of eggs, how many do you have? Is it 3 X 12 or is it 12 X 3 or is it 12 + 12 + 12? There is more than one way to get the answer.

The order of the output makes sense since the fetch is asynchronous and that callback (or then) won’t be executed until after the console.log("s"); is run. The flow inside show is:

  1. Start the fetch. This is asynchronous so continue on.
  2. Execute console.log(“s”);.
  3. Waiting … because there is nothing to do…
  4. Waiting … because there is nothing to do…
  5. Waiting … because there is nothing to do…
  6. Waiting … because there is nothing to do… seriously, to us it may be just half a second, but to a computer this is an eternity…
  7. Finally! The fetch returned with data! Now we execute the callback or the then.

So, Promise/then does the same thing (roughly) as a callback. There is also async/await - they all are ways to deal with asynchronous actions. Grabbing a file is a great example.