This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
Javascript noob here. Apologies if there are a ton of duplicate questions out there because it seems like this must be a fundamental js function thing, but I honestly can't find an answer to this. I'm trying to wrap an API GET call in a function, and I'm running into behavior that I don't understand. The code in question:
I'm using the node-rest-client package to call the mapquest geocoding API. I'm interested in the lat/long data only.
var Client = require('node-rest-client').Client;
If I make the GET call like this, I can access parsed as an object, which is what I want.
var address = 'New York'
var client = new Client();
var parsed;
client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
'key=' + mapquestKeys.consumer_key +
'&location=' + address,
function(data, response) {
parsed = data.results[0].locations[0].latLng
}
);
// parsed == {lat, long}
But if I wrap this in a function:
function geocode(address){
var client = new Client();
var parsed;
client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
'key=' + mapquestKeys.consumer_key +
'&location=' + address,
function(data, response) {
parsed = data.results[0].locations[0].latLng
}
);
return parsed
}
var address = 'New York'
parsed = geocode(address);
// parsed === undefined
parsed doesn't seem to be affected by the inner function; it's undefined. How can I return parsed as an object containing the data I want as in the first example? What the heck is going on here?
In:
function geocode(address){
var client = new Client();
var parsed;
client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
'key=' + mapquestKeys.consumer_key +
'&location=' + address,
function(data, response) {
parsed = data.results[0].locations[0].latLng
}
);
return parsed
}
var address = 'New York'
parsed = geocode(address);
// parsed === undefined
You never defined parsed outside of the scope of your function. Also you're returning parsed inside of the function before it's had a chance to retrieve from the GET request. If you wanted to do it this way, you'd need to put return(prased) inside the callback function of client.get. A better way to do it is to wrap it inside a Promise like so:
function geocode(address){
return new Promise((resolve, reject) => {
var client = new Client();
client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
'key=' + mapquestKeys.consumer_key +
'&location=' + address,
function(data, response) {
if(data){
resolve(data.results[0].locations[0].latLng)
}
else{
reject(response)
}
});
})
};
var address = 'New York';
var parsed;
geocode(address).then(function(latlong){
parsed = latlong
}).catch(err => {
console.log(err)});
Here, parsed will only evaluate to latlong once the Promise has been resolved (the GET request has returned successful). It will also reject the Promise if data of the GET request is NULL and return an error.
If you wanted to then do something with parsed you could include that in the .then() statement.
Learning how to code in Javascript means learning how to write code asynchronously. Promises help you treat things which are by default asynchronous as synchronous.
You never defined parsed in scope (externally to the function):
function geocode(address){
var client = new Client();
var parsed;
client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
'key=' + mapquestKeys.consumer_key +
'&location=' + address,
function(data, response) {
parsed = data.results[0].locations[0].latLng
}
);
return parsed
}
var address = 'New York'
var parsed = geocode(address);
Notice the var parsed = geocode(address);
you need to wrap this into a promise, or return the result with callback. Callback would be like this:
function call(arg, callback) {
client.get("http:////" + arg, function (data, response) {
callback(data.results[0].locations[0].latLng)
});
}
call("yolo", function (parsed) { console.log(parsed) })
promise is well described here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Related
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function() {
var messageData = "";
client.get("http://api.openweathermap.org/data/2.5/weather?q=Pune&appid=123234234234243242", function (data, response) {
console.log(JSON.parse(data));
messageData=data;
});
//how to set the response of that rest call to this messageData object
return messageData;
}
}
this method getWeatherStatus should return the rest response in json format.
Open for totally different suggestion to implement this kind of scenario.
My basic requirement is to use this REST call response and send to other functions.
In getWeatherStatus you use async function client.get. You need wait result from async function and only than return messageData. For this you can use deasync. Example:
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function() {
var messageData = "";
client.get("http://api.openweathermap.org/data/2.5/weather?q=Pune&appid=123234234234243242", function (data, response) {
console.log(JSON.parse(data));
messageData=data;
});
//We waiting for data.
while (messageData === "") {
require('deasync').sleep(10);
}
return messageData;
}
}
But, maybe, you should return Promise, not data.
Since get is callback function so you have to put your return messageData
in stead of messageData=data.
Code should be like
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function() {
var messageData = "";
client.get("http://api.openweathermap.org/data/2.5/weather?q=Pune&appid=123234234234243242", function (data, response) {
return JSON.parse(data);
});
}
}
I think you are facing difficulties to deal with with callbacks,
In the method getWeatherStatus, instead of returning the result, you should pass it to a callback function once the treatment is done.
If really you are required to return, galk.in answer seems to be a possible way.
Otherwise, check this out,
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function(then) {
var messageData = "";
client.get("/some/url", function (data, response) {
then(err=null, JSON.parse(data));
});
}
}
So you may call getWeatherStatus in such way,
// Somewhere else in your code
getWeatherStatus(function fnCallback(err, jsonData) {
console.log(jsonData) // process data here
})
As suggested, Promise are also a good alternative. but it is still async.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I have the below function that has an http request in angular. In the success part, I am trying to return the provided data, and return the value in my setTextFile() function, but it is undefined. I have checked that data is not null or undefined, so I know it contains information, but I don't understand why it's not returning that content.
var showFile = function (txtFile, host) {
var datData;
var url = 'rest/archive-viewer/spanish-discount/' +
$rootScope.currentEnv + '/' +
host + '/' +
txtFile;
$http.get(url).success(function (data) {
$scope.sendingMessage = "Getting file";
$scope.sending = false;
$scope.sendingMessage = "";
return data;
}).error(function (data) {
$scope.sendingMessage = "Creation failed";
$scope.sending = false;
});
}
$scope.pullFiles();
};
Here is my setTextFile function who's return value is undefined as a result of the showFile() return value.
var setTextFile = function (file,host) {
console.log("Is this null " + showFile(file, host));
return showFile(file, host);
}
That http request is asynchronous. What I would suggest you to do is assigning data to a scope veriable something like : $scope.setTextFile = data in the success function you have passed in ajax request. Instead you can make a function to set the data and trigger the function inside success function.
My goal: Show a default image if one does not exist.
My approach: I've created a helper that makes a server-side Meteor.call to check if the image url exists. The helper's intent is to either return a default image path (does not exist) or the dynamic path (image exists).
Where I'm stuck
Helper: On the client, I can successfully console.log the output
from the server-side method (result.statusCode). However, the helper does not return my
desired string in the template (/images/db/...etc).
Method: I'm getting a 200 results
status for ALL file paths, even ones that don't exist. I suspect
this has to do with iron-router's global NotFound template, but not
sure how to get around it. I tried using fs.exists but could never
get it to find a file (all responses were false).
Any and all suggestions most appreciated. If there's a simpler way to accomplish this, I'm all ears.
HTML:
<img src="{{imagePath key}}avatar.jpg">
My helper:
UI.registerHelper('imagePath', function(key){
//Build the Meteor.call url
var $host = document.location.host;
var $imgBaseUrl = '/images/db/'
var $assetPath = $imgBaseUrl + key + '/';
var url = 'http://' + $host + $assetPath + 'bg.jpg';
//Define the default image location
var $assetPathDefault = $imgBaseUrl + 'default' + '/';
//Call the server-side method
Meteor.call('checkIfImageExists', url, function(error, result) {
if (false) {
console.log('Error');
return $assetPathDefault;
} else {
console.log('Result: ' + result.statusCode);
console.log($assetPath);
return $assetPath;
};
});
});
Server-side method
Future = Npm.require('fibers/future');
Meteor.methods({
checkIfImageExists: function(url) {
check(url, String);
var fut = new Future();
this.unblock();
HTTP.get(url, function (error, result) {
if (!error) {
console.log('Found a file!: ' + url);
console.log('Result: ' + result.statusCode);
fut.return (result);
} else {
console.log(error);
console.log('Error: ' + error);
fut.return (false);
};
});
return fut.wait();
}
});
FWIW - I'm adding the "url check" to an old helper that simply inserted a string w/out checking if the image existed. Worked great.
UI.registerHelper('imagePath', function(key){
var baseUrl = '/images/db/';
return baseUrl + key + '/';
});
Your client–side helper doesn't return anything! Check out the structure you've used:
function a() {
...
Meteor.call(..., function b() {
return something;
});
}
The return something is a return statement of function b, while function a has no return statement – thus it returns undefined.
Meteor server-side methods are (and have to be) asynchrounous, while the nature of client-side Javascript implies that the helper methods are synchronous (there is no "wait" in the browser). Thus, to use a server-side method inside a client-side helper you have to take advantage of reactivity. Fortunately, it's pretty easy with a ReactiveDict:
var imagePathDict = new ReactiveDict();
UI.registerHelper('imagePath', function(key) {
...
if(!imagePathDict.get(key)) {
// the path was not initialized, fetch it from the server
Meteor.call(..., function(error, result) {
...
imagePathDict.set(key, result.assetPath);
});
}
// return the reactive path
return imagePathDict.get(key);
});
By the way, don't start your variable names with $ (unless you refer to a jQuery object), it's against conventions in Javascript.
I'm running the following within node.js:
function makeGetFunction(url) {
url = url + '?' + authstring;
console.log("get " + url);
request.get(url, function(e, r, data) {
var json = JSON.parse(data);
var resp = json.entities;
});
}
I would like to have makeGetFunction() return resp. I think the the answer lies somewhere with using a callback, but as I'm fairly new to asynchronous calls in javascript, I'm stumbling with how to properly pull it off. I haven't been able to find any examples or posts related to my question yet. Please excuse the newbie question.
Since the procedure involves asynchronous calls, the best choice is to follow the same pattern in makeGetFunction, by adding a callback argument:
function makeGetFunction(url, callback) {
url = url + '?' + authstring;
console.log("get " + url);
request.get(url, function(e, r, data) {
var json = JSON.parse(data);
var resp = json.entities;
callback(resp);
});
}
When using makeGetFunction, pass it a handler function instead of retrieving the return value:
makeGetFunction('www.myurl.net/what', function(resp) {
// do stuff with response
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
This is makinkg me crazy, i cant Get the outside variable Get the inside data
Sorry for the bad formating I'm writing from the phone, if someone can helpme out with the format I appreciate it
window.getReasons = function(line) {
var $reasons;
$reasons = "";
$.get(window.location.protocol + "//" + window.location.host + "/" + "allLineReasons.js?line=" + line, function(returnData) {
$reasons = returnData.toString();
return console.log("T_T ----->" + returnData.toString());
}, "html");
console.log($reasons);
return $reasons;
};
The most important thing for you to understand is that $.get() is ASYNCHRONOUS by default. So what is happening is that your console.log() and return statements that follow your call to get() are executing before the get() has returned it's value.
You might look to utilize the when() method here to handle the deferred object that is returned from get()
window.getReasons = function(line) {
var reasons = '';
$.when(
$.get(window.location.protocol + "//" + window.location.host + "/" + "allLineReasons.js?line=" + line)
).done(function(jqxhr) {
data = jqxhr[0];
reasons = data.toString();
});
console.log(reasons);
return reasons;
}
$reasons won't be updated until after the GET completes on the server and the response is returned. But your console.log will execute immediately after the request is made.