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.
Related
So, I wrote the following function:
function getData() {
var data;
$(function () {
$.getJSON('https://ipinfo.io', function (ipinfo) {
data = ipinfo;
console.log(data);
})
})
console.log(data);
}
The problem with the above is the 2nd console.log doesn't retain the info from the assignment inside the jQuery and logs an undefined object. I'm not exactly sure what is wrong, but I believe it to be something quite minor. However, as much as I've searched online, I haven't found an answer for this particular problem.
One line: Javascript is Asynchronous.
While many struggle to figure out what it exactly means, a simple example could possibly explain you that.
You request some data from a URL.
When the data from second URL is received, you wish to set a variable with the received data.
You wish to use this outside the request function's callback (after making the request).
For a conventional programmer, it is very hard to grasp that the order of execution in case of JavaScript will not be 1,2 and then 3 but rather 1,3,2.
Why this happens is because of Javascript's event-loop mechanism where each asynchronous action is tied with an event and callbacks are called only when the event occurs. Meanwhile, the code outside the callback function executes without holding on for the event to actually occur.
In your case:
var data;
$(function () {
$.getJSON('https://ipinfo.io', function (ipinfo) {//async function's callback
data = ipinfo;
console.log(data);//first console output
})
})
console.log(data);//second console output
While the async function's callback is executed when the data is received from the $.getJSON function, javascript proceeds further without waiting for the callback to assign the value to the data variable, causing you to log undefined in the console (which is the value of the data variable when you call console.log.
I hope I was able to explain that.!
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I know the title is a bit vague but I don't know how else to ask this and I'm having trouble wrapping my head around async javascript.
I'm writing a nodeJS app and I want to write a function that takes some xml input, converts it to JSON, cleans it up a bit, and returns it. I'm using the xml2js module to achieve this but I'm having some trouble because xml2js is asynchronous. Here's is a simplified version of my code:
function cleanUpData(xmlData) {
xml2js(xmlData, xml2jsCallback);
function xml2jsCallback(err, result) {
// do a bunch of additional cleanup
return cleanedUpJSON;
}
}
What I want is to be able to pass the xml to the cleanUpData function and get back the nice JSON, but since xml2js() is async, I can't really do that. I would need to do everything else I want to do inside the xml2jsCallback() function and no value would ever be returned. I'm just trying to write a simple utility function though. Is the answer that I just can't use xml2js for this purpose? I'd really appreciate some insight because I'm pretty sure I must be unfamilair with some js coding pattern that will accomplish what I need.
Callback syntax:
function cleanUpData(xmlData, callback) {
xml2js(xmlData, function(err, result){
callback(result);
});
}
cleanUpData(xmlData, function(jsondata){
// do stuff here with jsondata
});
Promise syntax:
function cleanUpData(xmlData) {
return new Promise(function(done){
xml2js(xmlData, function(err, result){
done(result);
});
});
}
cleanUpData(xmlData).then(function(jsondata){
// do stuff here with jsondata
});
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
});
};
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.
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.