Function returns undefined [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am relative new to node.js and I ran into a problem where a function is returning undefined. I use console.log to make sure that it returns the proper value and it does. But in the script that makes the call to the function shows as undefined. I think this may be an issue with async programming? I am trying to learn more on how promises work in node.js. What am I doing wrong?
The reason why I believe that it is a problem with async is because console.log is printing to the console undefined before the console.log in getCurrentFrameName();. var name is being assigned undefined.
frameHandler.switchToFrame('top_page');
var name = frameHandler.getCurrentFrameName();
console.log(name);
The console.log in this method prints to the console after the console.log in the code above. The value printed to the console of name is top_page.
this.getCurrentFrameName = function()
{
driver.executeScript('return self.name').then(function(name) {
console.log(name);
return name;
});
};

You can do this:
this.getCurrentFrameName = function(callback) {
driver.executeScript('return self.name').then(function(name) {
return callback(name);
});
};
and then call it like this:
frameHandler.getCurrentFrameName(function(name) {
console.log(name);
});
this will fix your problem, but yes, is a sync problem.

Yes, this is an issue with asynchronous programming. You cannot return a value from an asynchronous callback.
This is because the callback waits for the asynchronous script to execute, and so, node immediately passes control to the next line after the callback.
In your case, console.log(name); gets called before the callback is executed. Hence, the undefined.
The simplest solution to the current situation is to perform the necessary computations within the callback itself.
However, in more complicated situations (such as, callback within callback) you can easily end up with what is known as callback hell.
There are several ways to deal with callback hell: one of them is something called Promise.
What a Promise does essentially, is that it brings a sense of linearity to the code, thus making it easier to understand and maintain.
In your case, you can do this:
this.getCurrentFrameName = function() {
var myPromise = driver.executeScript('return self.name');
myPromise.then(function(name) {
// Do all computation with `name` here
});
};

Related

What is the use of the .then function in javascript? [duplicate]

This question already has answers here:
jQuery deferreds and promises - .then() vs .done()
(11 answers)
Closed 7 years ago.
There is not much answer for this simple question that I have. My main question is that I have seen the .then method used a lot in JavaScript and I know the main thing where randomobject.then(//This returns success, //this returns failure). But there are things that I don't get such as the code here:
var success = function (response) {
return response.data;
};
var error = function (errResponse) {
$log.error(errResponse.data.Message);
};
function getsomeData() {
var url = baseUrl + 'api/somedata';
return $http.get(url).then(success, error);
}
First off in that code I'm wondering how the var success knows what data it is getting and the same with error. It says response.data but what is response? It's probably the result of the http.get but that doesn't make much sense code wise. Also it seems that when I have a function for example.
getsomeData returns what it returns. Why doesn't it work if I do the ff:
var dataHolder = randomAngularService.getsomeData()
it returns an object that holds a data under $$state but somehow the .then makes it work if you do the ff:
randomAngularService.getsomeData().then(function (response) {
if(response != null) {
console.log('got the data');
$scope.meeData = response;
}
});
I thought the .then only takes two parameters? This is what's confusing me.
Also is the .then property a JavaScript method or a jQuery one?
It's used to replace (or provide an alternate way) the old callback mechanism with a cleaner way to handle asynchronous requests, instead of passing your callbacks as parameters, you can chain your function with .then, given function will be executed once the promise gets resolved.
Anyhow, this is just a basic explanation, you should really get into the books of promises for more info.
I'm lazy to explain the whole promise thing, but just to answer question about .then
The 2 arguments inside .then actually means "call this function when the promise is resolved(success)/rejected(failed)"
About the arguments inside the functions, they should be specified in the API, because the caller (for instance $http.get) get to decide what to pass when calling that function.

Scope in JavaScript / jQuery [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I've clearly been writing too much CoffeeScript, as I am now realizing I do not have even a basic understanding of scope in pure JS.
After playing for a while, I cannot figure out the problem with the following--
$(document).ready(function() {
var myUrl = "http://notimportant.com/"
var photos = getPhotos(myUrl);
console.log(photos); //undefined
});
function getPhotos(url) {
var a;
$.get(url, function(data) {
a = data["photoset"]["photo"];
console.log(a); //my object
});
return a;
}
If I put a console.log(a) statement on the line right below 'var a = data["photoset"]["photo"];' it shows that it properly makes the GET request I'm looking for. But I'm finding it impossible to pass that object back to my main block of code, where I want to manipulate it.
Thanks in advance.
The reason photos is undefined is not because of scopes. Its because $.get is executed asynchronously. $.get() returns jqXHR object instead of an HTTP response.
onSuccess callback should be passed to getPhotos() in order to make it work correctly. Alternatively when().then() construct could be used.
$(document).ready(function() {
var myUrl = "http://example.com/";
getPhotos(myUrl, renderCatPhotos);
});
function getPhotos(url, onSuccess) {
$.get(url, onSuccess);
}
function renderCatPhotos(data) {
var a = data.photoset.photo;
console.log(a); // a is always available
}
note: you might not even need getPhotos function. You can simply $.get(url, onSuccess); in $(document).ready() instead.
Its not a matter of scope, its a matter of that you are returning an undefined variable before the $.get defines it. Consider making photos a global, then setting it in the $.get success function instead of setting it to 'a'. Inside the success function, you can then issue calls to other functions that would control displaying/processing the photos.

Return promise value [duplicate]

This question already has answers here:
setting a variable to get return from call back function using promise
(2 answers)
Closed 8 years ago.
I'm new to Promise's and I'm trying to wrap my head around getting the value.
Here's an idea of what I'm trying to do:
API = {
get: function() {
return new Promise(function(res) {
setTimeout(function() {
res('foo')
}, 1000)
})
}
}
var foo = API.get()
console.log(foo)
It's important that var foo = API.get() remains as it is.
Any idea what to do here?
Promises are still asynchronous. You still can't inspect their value in synchronous code.
You need:
API.get().then(function(result) {
// Resolved value from the Promise object returned by API.get()
console.log(result);
});
API.get() returns a promise object, you then invoke the .then() method on that object.
Another more verbose way would be:
var fooPromise = API.get();
fooPromise.then(function(result) {
console.log(result);
});
Promises are about something happening in the future; you cannot examine their eventual values now unless you are in possession of a time machine.
I am not suggesting you do this, but merely for didactic purposes, if you really want your code to function as you seem to, you could redefine console.log to be promise-aware:
console.log = function() {
var old_console_dot_log = console.log.bind(console);
return function(maybe_promise) {
Promise.resolve(maybe_promise).then(old_console_dot_log);
};
}();
(This version only handles one argument; handling more is left as an exercise.)
Now when you say console.log(foo), it will log the resolved value of foo, but only when it is good and ready, one second from now.

Returning array from d3.json() [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
As a JQUERY/d3-noob, it seems I cannot figure out how to make this work:
supdog = d3.json(dataPath, function(jsondata){
return jsondata;
})
console.log(supdog);
Thanks in advance.
Besides the fact that your problem description is very terse, the problem seems to be your assumptions about what is returning what.
The function d3.json() is an asynchronous function that directly returns (with an undefined value I assume). Only when the data is received from the backend, the callback function you passed to it will be called. Obviously the context is different here and the return value of your callback will not automatically become the return value of d3.json (as this one has returned "long" before already).
What you want to do is probably something like:
var jsondata;
d3.json(dataPath, function(dataFromServer) {
jsondata = dataFromServer;
}
console.log(jsondata);
Update 1:
Obviously, the above example is still not fully correct. The call to console.log() is made directly after the d3.json() returned. Thus, the server might not have sent the reply fully yet. Therefore, you can only access data when the callback is returned. Fixed example:
var jsondata;
function doSomethingWithData() {
console.log(jsondata);
}
d3.json(dataPath, function(dataFromServer) {
jsondata = dataFromServer;
doSomethingWithData();
})
For a (somewhat stupid, but) working example see: http://jsfiddle.net/GhpBt/10/
Update 2:
The above example demonstrates in which order the code is executed but does not really deserve a price for most beautiful code. I myself would not use this "global" variable and simplify the above example to:
function doSomethingWithData(jsondata) {
console.log(jsondata);
}
d3.json(dataPath, doSomethingWithData);
Note how doSomethingWithData is directly passed to d3.json in stead of calling it separately in an anonymous inner function.
Note: This is not a particular problem of d3.js. Basically, all javascript functions that are asynchronous are likely to behave in a similar way. If they return something, it will not be the return value of the passed callback.
Solutions do not work anymore, if you start with the current d3 version. New solution -> Code within d3.json() callback is not executed
Then it must be...
d3.json("filename.json")
.then(function(data){
console.log(data);
});
I'm aware that this is a very old post, but I've faced a similar problem recently, and found the following solution, which might worth sharing:
In my case the JSON file's syntax was broken. By default, no errors pop up in the browser in this case, unless you enhance the function suggested by #BertjanBroeksema with errorhandling. Something like this:
function doSomethingWithData(error, jsondata) {
console.log("error:", error)
console.log(jsondata);
}
This way you'll see if there was something wrong with the processing of the JSON file.

Function return async response [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
Like a person asked here (but his solutions as to call a nother function) https://stackoverflow.com/a/10796326/315200 ...I would like to know if its possible to have a function which doesn't call a second function on response of an async request, but simply return when the async request responses.
Something like this maybe:
function callToFacebook() {
var fbResponse;
FB.api('/me', function (response) {
fbResponse = response;
});
return fbResponse; //Will return undefined because CallToFacebook is async
}
Isn't that possible some way, without calling another function??
What I'm trying to achieve is to have one function I can call with some parameters, which will return the response object from a async webservice, like FB.
In short, no. You cannot have an asynchronous function return a meaningful value synchronously, because that value does not exist at that time (as it is built asynchronously in the background).
You can, however, return a Promise object, representing the "potential return value" of the asynchronous operation, and bind a function to that object using done() or similar. That way, your function gets return semantics (instead of having to chain the control flow into a callback), and remains asynchronous.
No, it's not possible.
You can't return value that is returned from async operation.
Think about it, you tell 10 people to have one mile running contest, they start now, will finish in one minute +-, but you want to know the answer now, it's not possible unless you're cheating...

Categories

Resources