Javascript Callback - javascript

I have the functions below:
(Normally I get the variable msg by doing some query on a XML Object)
function getMsg(callback) {
var msg = "test";
callback(msg);
}
function msgDone() {
var message = null;
getMsg(function(msg) {
message = msg;
});
return message; //Why is message undefined here?
}
My problem is that I get an undefined on message. I have tested the function getMsg(), and it returns the right value.
How will I make the msgDone to return the message that I get from callback? So that it doesn't return undefined?
Thanks

Why is message undefined here?
It won't be, in the code in the question, but my guess is that the real getMsg is an asynchronous operation. That is, when you call it, it starts the process of getting the message but that process completes later, not right away. (For instance, a typical ajax call is like this.)
In that case, the reason message is undefined in the location you marked is that the callback hasn't been called yet, so nothing has ever assigned to message. You can't return the result of an asynchronous call from a function; instead, you have to provide a callback mechanism of your own (simple callbacks, or promises, or similar). E.g.:
function getMsg(callback) {
// Do something asynchronous...
// It's done, call the callback
callback(/*...the data retrieved asynchronously...*/);
}
function msgDone(callback) {
getMsg(function(msg) {
// Presumably you do more processing here...
// ...and then call the callback
callback(msg);
});
}
Then, instead of:
var msg = msgDone();
doSomethingWith(msg);
doSomethingElseWith(msg);
you do:
msgDone(function(msg) {
doSomethingWith(msg);
doSomethingElseWith(msg);
});

Related

How do I get result from function with a get request?

I have a piece of code that submits a GET request to another part of my website in a function.
function getStatus(ID) {
$.get('/api/'+ID+'/info', function(statusCallback) {
return statusCallback;
});
}
console.log(getStatus(ID));
What I would expect this code to return and then log would be the information that I need.
What I actually get in console log is
undefined
What can I do to get the actual result?
You're doing async operation. In your case using callback. If you want to print statusCallback, you have to console.log it like Christos mentioned.
Also
console.log(getStatusId())
will return undefined because it's default value returned from the function that has no explicit return. Your function has no return statement, it's only calling some async method.
Btw, try promises instead of callbacks if you can ;)
With ES7 you can use async await
async function getStatus(ID) {
$.get('/api/'+ID+'/info', function(statusCallback) {
// This is executed in the future, but await knows how to deal with it
return statusCallback;
});
}
console.log(await getStatus(ID));
They are a good practice to get started with, because the code gets a lot easier to read.
You need to change your functions as below:
function getStatus(ID) {
$.get('/api/'+ID+'/info', function(statusCallback) {
console.log(statusCallback);
});
}
The function you pass as the second parameter of your get call is called success callback. It will be called, once the get request that is issued on each call of the getStatus function completes successfully. Only then you have access to what the server returned and you can fairly easy access it as above.
Update
If you want to return the data that server sends you have to declare first a variable
function getDataById(ID){
function callback(data){
return data;
}
$.get('/api/'+ID+'/info', function(data) {
return callback(data);
});
}

How to block calling function while multiple asynchronous calls are executed, then contiune processing the collected data?

I would like to process an XML file in JavaScript, read every sheet asynchronously (because oviously it would be faster), and return the final result. I have the parser functions, I got stuck on the part when I would like to wait for every async call to finish, then return the result. A callback isn't the best practice for me in this case, because this function would be called at the beggining of another module, where I wouldn't like to put the rest of the code (let's say for example 500 lines) in a callback.
I have tried many approaches, the last one looks like the one below. But it seems to result in an infinite loop. All the other attempts returned undefined value, because the caller function ended before async calls would finish, and the accumulator haven't got any value.
1. To collect every async call's result, I used promise.
function getAllSheets(callback) {
accumulator = {};
promise.all([
processOneSheetAsync(workbook, sheetname1, ..., callback(data) {
accumulator.one = data;
}),
processOneSheetAsync(workbook, sheetname2, ..., callback(data) {
acc.two = data;
}),
/* some more function calls */
]).then(function(result) {
callback(acc);
});
}
Note: processOneSheetAsync() is function that returns a new Promise and calls the parser(), as expected.
2. Then I tried to wait for it's callback in a function like this:
function getResult() {
var result;
var callback = false;
getAllSheets(function(data) {
result = data;
callback = true;
});
while(!callback){};
return result;
}
I thought this would block the getResult() function until the variable callback is set to true. However, it seems that the while loop never detects the change of callback's.
Is there any good approach to solve this problem?
You should really use a callback. I'd probably do something like:
var myResults=[];
var waiting=0;
data.forEach(function(datum){
waiting++;
asyncCall(datum, callback);
}
function callback(result){
myResults.push(result);
waiting--;
if (waiting == 0){
doStuffOn(myResults);
}
}
However, if you're still against everything that is good in the world, you should check this, found here

Populating an empty object from data needed inside a function?

Just wanting to populate myObj with data from within the get request. According to my console.log(myObj) everythings seems to be their but can't access. I'm sure their is a simple answer to this. Thanks.
function getInfo() {
var myObj = {};
$.get("http://ipinfo.io", function(response) {
myObj.city = response.city;
myObj.region = response.region;
}, "jsonp");
console.log(myObj.city); //undefined
return myObj;
}
var myStuff = getInfo(); //Object {} just as I expected obviously.
console.log(myStuff) // Object shows all my key value pairs but -->
console.log(myStuff.city); // undefined why?
It is more suitable to use promises. You can try something like this:
function getInfo() {
var dfd = $.Deferred();
$.get("http://ipinfo.io", function(response) {
myObj.city = response.city;
myObj.region = response.region;
dfd.resolve(myObj);
}, "jsonp");
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
getInfo().done(function(myStuff) {
console.log(myStuff);
console.log(myStuff.city);
});
With promises the code is one idea elegant.
$.get is an asynchronous operation which means that it returns immediately (without running the code in your callback function first). The callback will only be executed at some point in the future when the GET request is finished. In the meantime the code following the $.get call will be executed.
What you're seeing is a result of a specific execution order in which the GET request happened not to finish before the following code was executed. In other words you have a race condition.
In theory , if the GET request finished almost instantly, it would be possible for the callback to execute before your log statements and therefore not print undefined. This is highly unlikely, however, as the time it takes to execute log instructions are much(!) less than what it takes to execute the GET request.
To fix the issue you need to ensure that you're log statements are always run only after the GET request is finished. The idiomatic way to do this in JS is with callbacks - e.g. pass a function which contains the code to execute and call it from inside the response handler:
function getInfo(callback) {
var myObj = {};
$.get("http://ipinfo.io", function(response) {
myObj.city = response.city;
myObj.region = response.region;
callback(myObj);
}, "jsonp");
console.log(myObj.city); //undefined
}
getInfo(function(myStuff) {
console.log(myStuff)
console.log(myStuff.city);
});
It return undefine because the request didn't response yet then the function returned the value. Your request was asynchronous meaning your function wont wait for your get request. it would return what ever myObj is.
You can try something like
function getInfo(callback){
$.get(..., function(res){
var myObj = …;
callback(myObj);
}
}
when ever your request is finished, it would call the callback function and pass in the myObj. so you need to pass in a anonymous function that expect 1 argument to pass in the myObj from the response
getInfo(function(data){
//data should be myObj
});

Async Javascript functions, not returning values

I'm having an issue that is burning my head. Basically this is the scenario:
I have a callController() function, which just simple use the jQuery.load() method to load a controller, after loaded, I can play with the returning parameters.
Now... in one of my controllers there is a validation rule I need to check in order to to allow the user to execute certain functionality, however, I create a function like this:
function myValRule() {
var val = callController('blablabla'),
response = "";
val.done(function(data) {
//my business logic
response = something;
}
return response;
}
As you imagine, response, even if It has a value, it returns undefined, so I set a timeout and console.log() it and now it has a value, but I cannot make to return this value even if I put the return into the setTimeout(). So basically when the method call this function to validate it finds it empty.
Can you point me on some direction to solve this issue?
Remember this is asynchronous! The return response; is long gone by the time .done() is actually called.
if you need the value returned in this fashion, look at either supplying a callback function in your myValRule function (that would be called from within .done()) or maybe look at using the $.Deferred api so you can mimic what callController(...) is doing.
Here's an example of both scenarios (with example call to myValRule):
Callback argument
function myValRule(callback){
var val = callController('blablabla'),
val.done(function(data){
var response = /* something */;
callback(response);
});
}
myValRule(function(response){
// here you have response
});
Using $.Deferred
(I assume it's jQuery since there's a .done call)
function myValRule(){
var df = $.Deferred(),
val = callController('blablabla');
val.done(function(data){
var response = /*something */;
df.resolve(response);
}).fail(df.reject);
return df.promise();
}
myValRule().done(function(response){
// here you have response
});

Callback function example

I am having a hard time understanding how the callback() function is used in the following code block.
How are we using callback() as a function, in the function body, when function callback() has not been defined?
What are the repercussions of passing true / false as parameters into the callback function below?
I appreciate any clarification, thanks in advance!
socket.on('new user', function(data, callback){
if (nicknames.indexOf(data) != -1){
callback(false);
} else{
callback(true);
socket.nickname = data;
nicknames.push(socket.nickname);
updateUserList();
}
});
When you pass a function as an argument, it is known as a callback function, and when you return a value through this callback function, the value is a parameter of the passed function.
function myFunction(val, callback){
if(val == 1){
callback(true);
}else{
callback(false);
}
}
myFunction(0,
//the true or false are passed from callback()
//is getting here as bool
// the anonymous function below defines the functionality of the callback
function (bool){
if(bool){
alert("do stuff for when value is true");
}else {
//this condition is satisfied as 0 passed
alert("do stuff for when value is false");
}
});
Basically, callbacks() are used for asynchronous concepts. It is invoked on a particular event.
myFunction is also callback function. For example, it occurs on a click event.
document.body.addEventListener('click', myFunction);
It means, first assign the action to other function, and don't think about this. The action will be performed when the condition is met.
I agree with you, the code in the snippet is very unclear.
The answers you got are great, however none refers to the actual use of callback in your code, and I would like to reference that specifically.
First, I will answer your question, and then I will elaborate on the complexity of it.
The answer
turns out socket.io are doing something very cool which is not the standard I know..
socket.io are passing the callback from the front-end to the backend!
So to answer your question what is this callback function - you have to look at your frontend code.
Look for code that looks like this
socket.emit('new user', data, function( booleanParameter ){
// what are you doing with booleanParameter here?
});
I assume that in your case true/false values are meant to pass back to the frontend if new user was added (true) or not (false)..
Or perhaps if the nickname is already in use or not so that the frontend can show an error string if it is..
Basically, #SumanBogati was right in his answer, but I felt it was lacking the step of finding the callback in the front-end due to socket.io's special treatment.
Further Suggestion To make your code clearer
Change name of parameter data to nickname
Add comments - why are you placing nickname on socket?
add documentation
Use jsdocs to explain what the callback is doing
/**
#callback NewUserCallback
#param {boolean} booleanParameter does something..
**/
and then on the function itself
/**
#parameter {string} nickname
#parameter {NewUserCallback} callback
**/
The complexity
Usually, in nodejs, a callback expects the first argument to be an error, so reading your code, it says
socket.on('new user', function(data, callback){
if (nicknames.indexOf(data) != -1){
///// THERE IS NO ERROR
callback(false);
}else{
///// THERE IS AN ERROR
callback(true);
/// do more stuff after the error
socket.nickname = data;
nicknames.push(socket.nickname);
updateUserList();
}
});
Not the pattern you'd expect, is it? I guess this is why you asked the question.
Still the question remains what socket.io's callback means, right? Perhaps their callback does not expect an error as first argument.
I have never used socket.io, and I was unable to find a documentation to clarify this. So I had to download their chat example and debug it ==> and so the answer I gave, they are passing the function from the frontend to the backend.
Socket.io should definitely stress this point in large font in their documentation under a title named "How does socket.io handle callbacks?" or "How does our callbacks work?".
Great question! Learned a lot from it!
I'll try to simplify with a "concrete" example (I hope).
Let's say I have a function that "calculates" the current day and I'll call that function each time I would need the current day ("Don't call us, we'll call you" or whatever).
var getCurrentDay = function (callback) {
var currDate = new Date();
callback(currDate, 'err');
});
};
getCurrentDay(function (returnDay) {
logger.info('Today is: ' + returnDay); });
A callback function, is a function that is passed to another function (let’s call this other function “otherFunction”) as a parameter, and the callback function is called (or executed) inside the otherFunction.
Here is my simple example for callback function
// callback add
function add(a, b){
console.log(a+b);
}
// Main function
function getInput(cb) {
c = 5+5;
d = 6+6;
if (typeof cb === 'function') {
cb(c, d);
}
}
getInput(add)
For detailed explanation refer the this link
Without thinking too much, see the following example.
In the following example, I just call the print function from the add function.
function print( ans ){
console.log(ans) ; // 7
}
function add(a, b){
print(a+b) ;
}
add(2,5);
What if I use the print function as a parameter? Without using print function from global scope I just pass the print function as an argument.
function print( ans ){
console.log(ans) ; // 7
}
function add(a, b, callback){ // here callback = print
callback(a+b) ;
}
add(2,5,print); // print function as a parameter
Generally, JavaScript allows function as a parameter.
So any function that is passed as an argument is called a callback function.
I think now callback is understandable to you.
Callback function mean call after another:)
doHomeWork('math',alertMsg);
Above line said 1. call doHomeWork and then call 2. alertMsg, that's it.:)
function doHomeWork(subject,callback){
console.info("study: "+subject);
callback();
}
alertMsg = function(){
console.info("alert");
}
doHomeWork('math',alertMsg);
Output:
study: math
alert
A callback is any function that is called by another function using parameter
Here a query for you Suppose that Consider how programmers normally write to a file:
- `fileObject = open(file)` //now that we have to wait for the file to open, after that we can write to this file*
- fileObject.write("We are writing to the file.") // but i want to write , not wait
This case - where callbacks are helpful:
//we can pass **writeToFile()** (a callback function) to the open file function
- fileObject = open(file, writeToFile)
//execution continues flowing -- we do not wait for the file to be opened
//once the file is opened we can write to it, but while we wait we can do other things
Function inside a function is called a callback function. Or let me say that the inside function which is present inside the parent function is called the callback function.
If you want to complete a task2 after task1. Then you can make task2 as the callback and this will run asyncronously
Here is one example where the usage of callback function is easy to understand.
A login function which performs user login with the server asynchronously.
Due to asynchronous call , we need to get the result of login once the date receives from the server.
const axios = require('axios');
function login(loginData,callbackSuccess,callBackFailure) {
axios
.post("/api/login",loginData)
.then((response) => {
callbackSuccess(response);
})
.catch((error) => {
callBackFailure(error);
});
}
function callbackSuccess(data) {
console.log("Login response :",data);
}
function callBackFailure(error) {
console.log("Login failed :",error);
}
let userData = {
username : "test",
password : "abcd123"
}
login(userData,callbackSuccess,callBackFailure);

Categories

Resources