According to this stackoverflow answer,
functions passed as parameters are always callbacks, even if the intention is that the function is called synchronously...
and I've learned the event loop mechanism which basically says that call back functions are push into a waiting queue and executed after synchronous code finishes(stack empty), however in the following code
function myfun(a, b, callback) {
console.log(a);
callback();
console.log(b);
}
function cb() {console.log('hi')}
myfun(1, 2, cb) // result: 1 hi 2
the result is not 1 2 hi as I expected, from which I infer that only callback functions that fire some 'event signal' like setTimeout will be pushed into such queue but I can't find concrete reference to support it?
"Callbacks" are usually used in conjunction with asynchronous processes like ajax requests or event handlers attached to the ui. We call them "callbacks" in these cases since they need to be executed after something else and it is clear where the program's logic will pick back up this "call" after the async process is complete or triggered brings us "back" here.
Using setTimeout() you can add to the event loop stack. Using a promise you can invoke the stack on the event loop as you wait for an asynchronous process to finish.
Your code doesn't do anything to interrupt the synchronous flow of the code. This snippet shows how even though we have added a timeout of 0 which should delay the action, we can await a promise to allow the event loop's stack to run.
function myfun(a, b, callback) {
console.log(a);
callback();
console.log(b);
}
function cb() {
console.log('hi')
}
myfun(1, 2, cb) // result: 1 hi 2
// same behavior as above
function myStaticFun() {
console.log(1);
cb();
console.log(2);
}
myStaticFun();
// now same as before using a promise to wait a moment and the event loop stack is invoked during the pause
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function myEventLoopInvokingFun(a, b, callback) {
console.log(a);
setTimeout(callback, 0)
await sleep(0);
console.log(b);
}
myEventLoopInvokingFun(1, 2, cb);
It does not necessarily mean that every a callback is asynchronous and must be put into a some task queue and to be executed once synchronous code pieces (call stack is empty) finishes. The callback functions dealing with Promises are candidates for task queue. For instance in your case; cb function simply runs in a synchronous manner; so that the result is 1 hi 2 as you indicated; however if we modify your code as follows:
function myfun(a, b, callback) {
console.log(a);
window.setTimeout(callback, 0);
console.log(b);
}
function cb() {
console.log('hi');
}
myfun(1, 2, cb) // result: 1 2 hi
this will result in 1 2 hi. Even though I set the timeout to just 0 milliseconds; cb function will output after the second console.log within myfun function. I would recommend you to take a look at MDN and this good explanation of call stack, event loop, and task queues. Hope this helps.
Related
This question already has answers here:
Why is the method executed immediately when I use setTimeout?
(8 answers)
Closed 1 year ago.
const eventLoop = () => {
console.log("Start");
setTimeout(() => console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
Output:
Start
End
Settimeout
But for
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
Output:
Start
Settimeout
End
Please help me to understand JS execution stack and event loop in above scenario
Have you executed console.log() inside developer tools?
I think it was very confusing at first time. it has many relationship with this question.
console.log("Hello, World!");
// returns undefined
It's a kind of expression returns undefined with side effect.
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
console.log("Settimeout") expression in above code is executed immediately, before setTimeout function called.
Therefore, it is not related with event loop.
const eventLoop = () => {
console.log("Start");
setTimeout(() => console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
In this example you :
console.log is put on function call stack, since stack is empty it is executed.
The function passed to setTimeout is added to the tasks queue. The thing to note here is that the delay will be atleast 0ms and it is not guaranteed that the function will be called after 0ms.
Now this console.log is called using the stack.
Now, since the stack is empty and the execution has completed items from the queue are picked. So the function passed in step 2 is picked and called.
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
In this example, step 1 and 3 are exactly same as example#1. But, in step 2 you are not passing any function inside setTimeout you are simply calling console.log() there.
() => console.log("Settimeout") is not the same as console.log("Settimeout").
First becomes ->
() => {
return console.log("Settimeout");
}
Second is simply, console.log("Settimeout").
In short, when in second example execution reaches line 2, console.log() is executed. But in first example, a function is passed to setTimeout which has the responsibility of calling console.log().
The following URL explains very well the event loop.
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
This one explains what parameters receives the SetTimeOut function
https://www.w3schools.com/jsref/met_win_settimeout.asp
When you use the function in the first of your cases, the function passed as parameter is called after the next cycle in the event loop, it means you have to pass a function to be called after the cycle, but if you put "console.log" you are performing that function instantly, so there is no function to be called in the next cycle.
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);
This question already has answers here:
How can I pass a parameter to a setTimeout() callback?
(29 answers)
Closed 3 years ago.
Example of setTimeout being executed after a synchronous code is below it
console.log('hello');
setTimeout(() => console.log('timeout'), 0);
console.log('end');
Console Output:
hello
end
timeout
Async:
function asyncForEach(array, callBack) {
array.forEach(x => setTimeout(callBack(x), 0));
}
asyncForEach([1,2,3,4], (i) => console.log(i));
console.log('end');
Console Output:
1
2
3
4
end
Synchronous:
[1,2,3,4].forEach(x => console.log(x));
console.log('end');
Console output:
1
2
3
4
end
I am trying to better understand the event loop and the task queue, and after watching a well recommended video (https://www.youtube.com/watch?v=8aGhZQkoFbQ) came across the semi statement of: "Callbacks can be synchronous and asynchronous". The speaker went on to demonstrate how the synchronous way would not end up going through the task queue, and therefore the event loop, so everything remained on the stack. However, the asynchronous way would cause the task queue to be populated with the eventual return of the setTimeout callback, which would make any synchronous below code executable since the event loop has to wait for an empty stack to insert the returned callback.
When running the above code (something I stole from him and also edited, so it could be a wrong addition on my part), the asynchronous way produces the same results as the synchronous way.
Could someone help explain why the asynchronous way does not act as the very first setTimeout example and/or provide explanation of how regular callbacks (such as the array helper methods) are not inserted into the task queue therefore never messed with by the event loop?
Your "asynchronous way" isn't asynchronous, because you called the function and passed its return value to setTimeout:
function asyncForEach(array, callBack) {
array.forEach(x => setTimeout(callBack(x), 0)); // <-- callBack(x) calls callBack immediately
}
asyncForEach([1,2,3,4], (i) => console.log(i));
console.log('end');
If you want it delayed, make a function to pass to setTimeout that it can call later:
function asyncForEach(array, callBack) {
array.forEach(x => setTimeout(() => callBack(x), 0)); // <-- Makes closure that calls callBack(x) later
}
asyncForEach([1,2,3,4], (i) => console.log(i));
console.log('end');
There's a bug in your asyncForEach function. You're calling callBack(x) immediately and then passing the result of that function (undefined) to setTimeout.
Say I want to create some callback hell, such as :
function handleUserInput(callback) {
...
}
function get(uri, callback) {
...
}
function processResponseInWorker(callback) {
....
}
function updateIndexedDB(callback) {
...
}
function updateUI() {
...
}
handleUserInput(get(hot_uri,processResponseInWorker(updateIndexedDB(updateUI()))));
This is mostly academic since the stack only gets 5 high.
In fact, is there even a stack at all? Since these calls will return immediately, and the callback will only be invoked, outside of these contexts, by whatever asynchronous tasks these functions perform.
Okay, just say there IS a call stack here, if each callback was forced to execute inside a setTimeout(func,0) then the calling function would return immediately, the whole chain would return immediately and the functions would be executed off the setTimout queue.
Is that correct?
setTimeout will not call the provided functions unless there is no other code running.
As is demonstrated in this code the timeout, although it is a 0 millisecond delay, will not execute until no other code is being executed. That is the nature of classic javascript (synchronized).
console.log(1);
setTimeout(function() {
console.log(2);
}, 0);
console.log(3);
for(var i = 4; i < 100; i++) {
console.log(i);
}
Initially lets assume the depth is 0. Let's assume that no functions other than the callbacks and the functions in the original code are called
updateUI()
Call the function updateUI our depth becomes 1. We return a function from this function and our depth becomes 0 again and we have something that essentially looks like this.
updateIndexedDB(function(){})
So we call updateIndexedDB and our depth becomes 1 which calls the provided callback function and our depth becomes 2. The callback returns and depth becomes 1 and updateIndexedDB returns a functions so that we have something looks like this.
processResponseInWorker(function() {})
Similar process occurs until we have this
get(hot_uri, function() {})
Again the same thing until we have this
handleUserInput(function() {})
Without using timeout the max depth i observe is 2 but using timeouts on your callbacks (which i don't know if you can do because i don't know if your callbacks give you future callbacks) your max is 1 since the callbacks will individually be executed after all code has been executed (on their own stack).
I feel like you meant to write your code this way
handleUserInput(function() {
get(hot_uri , function() {
processResponseInWorker(function() {
updateIndexedDB(function() {
updateUI();
});
});
});
});
which would result in a depth of 6 again unless you use timeouts which would result in a stack size of 1.
I am new to node.js and relatively new to javascript. I have understood how callbacks works and wanted to try out a function myself. Here is my code:
MyScript.js:
var calledfunction = function()
{
console.log("This is a called function");
for(i=0;i<1090660;i++)
{
console.log(i);
}
console.log('done');
};
var sayHello = require('./sayhello.js');
objhello = new sayHello();
objhello.setupSuite(1,calledfunction);
console.log('Next statement;');
sayhello.js
var _ = require('underscore');
module.exports = exports = CLITEST;
function CLITEST(param1,param2)
{
}
_.extend(CLITEST.prototype, {
setupSuite: function (here,callback) {
console.log(here);
console.log('This is a callback function');
callback();
}
})
The above program is run by executing > node Myscript.js
My question is : the for loop consumes 50 secs to execute and print all the numbers in the console and then only executes the line "Next statement" which is outside the callback function .
Why is this happening? because I read theories saying that the immediate statements will be executed without having to wait for the function to get executed.
The ideal output should have been : print " Next statement" and then print the contents of the for loop
but in the above case it is vice versa ?
This is not a real callback, but rather a simple function call. Function calls are obviously synchronous, as the following statements may rely on their return values.
In order to may the callback async you can use: setTimeout or setImmediate, depending on the actual use case.
See also: Are all Node.js callback functions asynchronous?
As pointed out by one of the commenters, your code is executed in a synchronous fashion. The function calls are executed one after the other, thus no magic is happening and the console.log('Next statement;'); call is executed after the execution of the callback. If you were in a situation in which you had to call a function which executed an asynchronous call (i.e., an AJAX call with a callback) then yes, you would expect the subsequent console.log to be executed right after the asynchronous call.
In other words, in your case the code represents a simple function call, while an asynchronous call would offload the computation of the callback somewhere else, thus the execution of the code where the callback function was called keeps going by printing the statement and won't wait for the execution of the callback.