I have nested callback that is setup as following:
function submitForm() {
BuildContent($('#Content').val(), '', true, submitForm)
PerformSubmit();
}
function BuildContent(textWithUrl, textSource, isSubmit, callback) {
console.log("GetWebContent in Progress");
GetWebContent(sendurls, BuildContent)
console.log("GetWebContent done");
callback();
}
function GetWebContent(content, callback) {
$.ajax({....
sucess:function(msg) { .....
callback();
}
}
expected outcome is when submitForm is called it calls Build Conetent which calls GetWebContent. o*nly after the ajax call in inside GetWebContent is sucessfull then only PerformSubmit(); is executed.* for some reason it loops and JS hangs and becomes unresponsive and BuildContent console logs keeps prininting in loop.
The BuildContent callback called just after the console.log is the function submitForm
which promptly calls BuildContent hence an endless loop.
Without doing an in-depth analysis, I would suggest removing the call callback at the end of BuildContent and passing it instead as the second parameter of the call to GetWebContent.
After a bit more thought, in submitForm teh callback you send to BuildContent should be PerformSubmit. My alterations to buldContent stand.
It looks like you have a misunderstanding of how callbacks work. When a callback returns, it does not resume execution where it left off. The function calling the callback finishes immediately.
You need to structure the code like so:
function submitForm(){
BuildContent($('#content').val(), '', true, performSubmit);
}
function BuildContent(textWithUrl, textSource, isSubmit, callback){
console.log("GetWebContent in Progress");
GetWebContent(sendurls, callback);
}
function GetWebContent(content,callback){
$.ajax({...
success:function(msg){ ....
console.log("GetWebContent done");
callback(); <-- performSubmit is being called here,
after all of the asynchronous work is done
}
});
}
You'll notice that I pass the performSubmit along as the callback to each of these functions, and then call it in the success function.
Anything AFTER the GetWebContent call within BuildContent will execute immediately, so you can't expect the second call to console.log to be AFTER the ajax request is finished.
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);
const getData = (cb) => {
setTimeout( () => {
cb({ data: ['there', 'is', 'stuff', 'here'] })
}, 100)
}
getData( data => {
console.log(data);
});
Here is the example of the javascript callback. Could some one let me know how this functions is executed into the javascript callback?
Here what is the function inside getData(cb) ? How it will be executed ? How the functions is passed as callback inside cb and return to the console.log
Regards.
The function inside getData is a callback being passed to setTimeout, which is one way to schedule a call to a function to happen in the future. In this case, it's asking for that callback to happen roughly 100ms later. getData returns before that happens.
The setTimeout callback is a closure¹ over the context where it's created, which means it has access to cb even after getData has returned. So when the browser's timer calls the callback, the callback can call cb. The call to cb uses an object literal to create an object to pass to cb.
In the call to getData, the author is passing a function as cb that logs the data it receives.
So:
getData is called, passing in a function that will log the argument it gets.
getData calls setTimeout to schedule a callback in about 100ms, passing in another function for the timer to call.
getData returns.
About 100ms later, the browser's timer subsystem triggers a call to the callback passed to setTimeout.
That callback creates an object and calls cb, passing the object to it.
That callback (the one passed to getData) logs the data object it receives.
¹ "closure" — see: SO, my anemic blog
In order to understand the code you can just simplify it by naming the anonymous functions. One example could be:
function logData(data) {
console.log(data);
}
const getData = (cb) => {
// `cb` is `logData` function when `getData` is called
function timeoutCallback() {
var data = { data: ['there', 'is', 'stuff', 'here'] };
cb(data);
}
setTimeout(timeoutCallback, 100)
}
getData(logData);
Does that make sense?
1- first global execution context created
2- get data function will be called then it will wait for 10 seconds inside the event loop then it will be come to execution context and printed to console.
I have two functions.
function function_a(callback) {
if (some_condition===true) {
callback // fire the callback
}
}
function function_b() {
... do some action
}
My script calls:
function_a(function_b());
Meaning, the callback in function_a() will be the execution of function_b().
However I do not always want function_b() to fire. I only want it to fire when some_condition===true (as in the function_a() body).
The problem right now is that whenever I feed a callback function into the parameters of another function it fires it automatically without running through the script of the function to determine whether or not the callback needs to fire at all.
Is there something I am doing wrong or some different way to do this?
Thank you!
You need to call function_a(function_b);.
Right now you are not passing function_b itself, you are calling it immediately and passing in its return value.
Your function_a should do callback() rather than callback.
Parentheses cause a function to "execute" or "fire". So like Comptonburger said, drop the parentheses for the "script call", but add the parentheses on the callback.
function function_a(callback) {
if (some_condition === true) {
callback(); // parentheses do the "firing"
}
}
function function_b() {
// ... do some action
}
// Script calls:
// No parentheses on function_b because we
// don't want to "fire it" right here and now.
function_a( function_b );
You can also pass function_b() as a string and evaluate it after condition passes.
function function_a(callback) {
if (some_condition===true) {
eval(callback); // fire the callback
}
}
function function_b() {
... do some action
}
function_a("function_b()");
I've started recently to learn about javascript, and I saw a lot of callback functions.
What are those functions, why they are used and what for?
I will be happy to get really basic definition, because I wanna understand it because I realised that it is really important in js.
thanks :)
A callback function is a function you pass as an argument to another function.
The callback function will be called by the function you pass it to (or one further down the chain).
This is typically done when the function is doing something asynchronous, so you can't use a return value.
The main examples are for events:
// call someFunction when the document is loaded
addEventListener('load', someFunction);
or time related calls:
// call someFunction after 30 seconds have elapsed
setTimeout(someFunction, 30000);
As the name suggests, callback functions are anonymous or named functions that are passed as arguments to another function, or an AJAX call etc. and will be executed after a certain action is completed by the javascript engine.
For eg. You can pass a callback function to be executed once an AJAX call has returned with data. Ill use jQuery for simplicity :
$.ajax( {
url: "/my-api-path/",
data: myParams
}).done(myCallback);
Here, myCallback is a function that will be executed once the AJAX call completes. The callback function in this case will be called with the response object returned by the AJAX call. Notice how this callback has been passed as an argument to the .done method provided by jQuery's AJAX API.
In another example,
setTimeout(
function() {
alert("Im inside a callback function!");
}, 2000 );
Here the function that contains the alert is the first of the two arguments passed to the setTimeout method in javascript. The second being the amount of milliseconds after which this function should be executed. Since this function does not have a name it is called an anonymous function.
The same code could be re-written as :
var myCallback = function(){
alert("Im inside a callback");
};
setTimeout(myCallback, 2000);
Callbacks are executed immediately when the action completes. So after the engine encounters the setTimeout statement it will store the myCallback function in a reference and then continue execution after the setTimeout statement. Once 2 seconds elapse, it will realise its time to execute the callback so execution will jump to the callback. Then the alert will execute, the callback function will terminate and execution will continue back from where it was when 2 seconds elapsed and the engine jumped to the callback.
Hope this explains how callbacks work.
As we know we can pass different type of variable, object as function's parameter . In javascript if a function is passed as parameter then it is called Callback funbction.
The callback function is called on some event/condition till then the program can execute other code. The callback function would executed only when the particular event is occurred or particular condition is satisfied.
I'm attempting to use async.js to manage callbacks in an application. Below is an example of that code. However, I've run into a problem where the series of functions continues executing before one of the prior functions completes. For example, the resizeImage() function is still working when saveImageData() fires. But my intention is for the image to be saved only after it is resized. Shouldn't async.js handle this? If I have to pass a callback to resizeImage() what is the value of using async.js? Can someone show how using an async library is helpful in the example that I've given?
if (req.files) {
//removed some code not relevant to the question
async.series([
function (callback) {
model.saveImageData(tempPath, originalImage, s3Headers);
callback(null);
},
function (callback) {
var src = tempPath;
dst = path.dirname(tempPath) + "\\" + newImage;
model.resizeImage(src, dst);
callback(null);
},
function (callback) {
//the next function gets called before resizeImage() finishes executing
model.saveImageData(dst, newImage, s3Headers);
callback(null);
}
]);
}
Most likely saveImageData and resizeImage are non-blocking, asynchronous calls. Given they're doing I/O.
So you call resizeImage, it starts processing, returns control while it waits for IO, and your code immediately invokes the async.js callback that indicates that the function has finished it's work.
Instead, you should only call the async callback parameter after saveImageData and resizeImage complete, which means creating and using a callback function:
// this is just a guess at the api.
async.series[function(callback) {
model.resizeImage(src,dst,function() {
callback(null);
});
}];
You still have to ensure that the code inside each async function invokes the callback at the appropriate time.