This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm now trying to make get/post api request with axios javascript.But the problem is that my Api get function return the result before it receives data from server.here is my code
function Api(base_url) {
this.base_url = base_url;
}
Api.prototype = {
constructor: Api,
get: function (route) {
var url = this.base_url + route;
axios.get(url)
.then(
response => {
console.log(response.data.data);
return response.data.data;
})
return "hello";
},
post: function (route) {
}
}
And I call get function like this
api = new Api("http://localhost:8080/");
var data = api.get("post/get");
console.log(data);
Instead of waiting for reply from server,my function return "hello" as return data.Can someone help me why and how to solve this please?
Use this code:
Api.prototype = {
constructor: Api,
get: function (route) {
var url = this.base_url + route;
axios.get(url)
.then(function (response) {
console.log(response.data.data);
return response.data.data;
})
.catch(function (error) {
return "hello";
}
},
post: function (route) {
}
}
That's what it is supposed to do, I think.
I never used this Api, but with regular ajax requests, the function from which you send the request will return his value immediately independently from the request/response. The best way to do something once the request is completed, is to call what you need in the response callback.
AJAX requests are asynchronous, and there is no clean way to call a function wich executes an AJAX requests and make that very same function return your response data - unless you turn the AJAX request into a synchronous operations, but that's very very very bad practice.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
When attempting to use asynchronous calls, the response is undefined rather than returning back the expected response data.
You can see how to run into this issue with any of the following examples:
Fetch
const response = getDataWithFetch();
console.log(response);
function getDataWithFetch() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
fetch(url).then(response => {
return response.json();
});
}
Axios
const response = getDataWithAxios();
console.log(response);
function getDataWithAxios() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
axios.get(url).then(response => {
return response.data;
});
}
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
AJAX / jQuery $.get
const response = getDataWithAjax();
console.log(response);
function getDataWithAjax() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
$.get(url, (response) => {
return response;
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Promise
const response = getDataWithPromise();
console.log(response);
function getDataWithPromise() {
new Promise(resolve => {
const response = 'I am a response';
return resolve(response);
});
}
Overview
Asynchronous calls, such as HTTP get requests via fetch, axios, AJAX or other asynchronous calls via Promises all behave similarly in that what is returned by the time that the function reaches its last line is not actually the result that you want.
Explanation of Issue
This is because asynchronous calls do not wait for the call to finish executing before executing the next line:
Note that in all the examples below, I will be using fetch but the concept could easily be extended to the other call types.
getDataWithFetch();
function getDataWithFetch() {
console.log('start of outer function');
const url = 'https://jsonplaceholder.typicode.com/todos/1';
fetch(url).then(response => {
console.log('start of async function');
response.json();
console.log('end of async function');
});
console.log('end of outer function');
}
As you can see via Run code snippet, the outer function starts and ends before the async function starts. What is undefined being returned from getDataWithFetch() because it is hitting the end of the function, and has no return statement. If we change the code to add a return statement, we can see what part of the function call is actually being returned:
const response = getDataWithFetch();
console.log(response);
function getDataWithFetch() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
fetch(url).then(response => {
return response.json();
});
return 'hello world';
}
Now the function isn't returning undefined anymore, but it's not returning the fetch request response; instead, it is returning 'hello world'. This is because the fetch request is not blocking the rest of the getDataWithFetch function from executing. To understand why, we need to understand what fetch is doing behind the scenes.
Promises
Resolve
To do so, we need to understand Javascript Promises. There's a great beginner-friendly read on it here: https://javascript.info/promise-basics, but in a nutshell:
A Promise is an object that, when it finishes the asynchronous work, it will call the "resolve" function. Where "resolve" returns the expected data via resolve(dataToReturn).
So behind the scenes, fetch returns a Promise that will call resolve when the fetched data is retrieved, like so:
// just an example of what fetch somewhat looks like behind the scenes
function fetch(url) {
return new Promise(resolve => {
// waiting for response to come back from server
// maybe doing a bit of additional work
resolve(responseDataFromServer);
});
}
With that understanding, we now know that we need to return the call to fetch to actually return the Promise, like so:
const response = getDataWithFetch();
console.log(response);
function getDataWithFetch() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
return fetch(url).then(response => response.json());
}
The console.log is no longer returning undefined, but it's not returning the right response either. That's because getDataWithFetch is now returning the Promise object from fetch. It's time to get the response from resolve.
.then
To get the data passed to the resolve function, we need to use the then method on the returned Promise.
A Promise provides the method then to retrieve the value passed to resolve as such: myReturnedPromise.then(dataToReturn => { /* do something with the data */ });. then will only execute once the dataToReturn is ready to be handled.
Final Solution
So by using the then method, we can get the actual response printed to console:
getDataWithFetch().then(response => {
console.log(response);
});
function getDataWithFetch() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
return fetch(url).then(response => response.json());
}
And there you have it!
Overly Verbose Solution
If there was too much magic in what made that solution work, you can also see the breakdown of it by explicitly returning a Promise to be fulfilled:
getDataWithFetch().then(response => {
console.log(response);
});
function getDataWithFetch() {
return new Promise(resolve => {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
return fetch(url).then(response => {
resolve(response.json()));
// Note that the `resolve` does not have to be part of the `return`
}
});
}
Async and Await Solution
Recent improvements to Javascript have provided us with a more succinct way of handling Promises to make them appear synchronous instead of asynchronous. Note that the following code is equivalent to the above solutions, but much easier to read:
async function getDataWithFetch() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
const response = await fetch(url);
return response.json();
}
getDataWithFetch().then(response => {
console.log(response);
});
async and await are clean and powerful alternatives to explicitly dealing with Promises, especially when Promise Chaining is involved. I recommend reading more about them here: https://javascript.info/async-await.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I'm currently trying to do something with the Gmail-API but unfortunately I'm not able to create a getter method because the google functions are asynchronous.
So I basically have two functions:
function doSomething() {
let mailArray = [];
fs.readFile('credentials.json', (err, content) => {
mailArray = getBackupsMails(authorize(JSON.parse(content)));
});
// do something with mailArray
}
function getMails(auth) {
let mailArray = [];
gmail.users.messages.list({auth: auth, userId: 'me'}, function(err, response) {
let messagesArray = response.data.messages;
messagesArray.forEach((message) => {
gmail.users.messages.get({ auth: auth, userId: 'me', id: message.id }, function(err, response) {
message_raw = response.data.snippet;
text = message_raw.substring(16, 55);
mailArray.push(text);
});
});
});
return mailArray;
}
Unfortunately the mailArray is undefined. How can I get the filled array?
Since the API-call is asynchronous, you can only access the filled array once the API call has completed. Currently, return mailArray; gets executed before the API call is done.
To get the actual emails to the caller of getMails(), you will need to make getMails() asynchronous too - either with async/await, promises, or a callback.
As ponury-kostek said, see How do I return the response from an asynchronous call? for details.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am writing a class in JavaScript that sends HTTP requests for a specific URL. I'm trying to test that class with Mocha but for some reason, the method fetchUrl() returns undefined. I can't seem to figure out why. I literally started writing in JavaScript a day ago, therefore I am still trying to learn and adjust to it.
fetchUrl () {
var request = require('request')
var res
request(this.url, function (error, response, body) {
console.log('error:', error) // Print the error if one occurred
if (response.statusCode !== 200) {
console.log('received status code other than 200 OK')
this.error = true
}
res = response
console.log('statusCode:', response && response.statusCode) // Print the response status code if a response was received
// console.log('body:', body) // Print the HTML for the requested url.
this.html = body
})
return res
}
describe('Test Http request to google.com', function () {
it('should return 200', function (done) {
assert.equal(httpCon.fetchUrl().statusCode, 200)
done()
})
})
You should use Nock libray to mocking HTTP request.
const axios = require('axios');
module.exports = {
getUser(username) {
return axios
.get(`https://api.github.com/users/${username}`)
.then(res => res.data)
.catch(error => console.log(error));
}
};
And here test case:
describe('Get User tests', () => {
beforeEach(() => {
nock('https://api.github.com')
.get('/users/octocat')
.reply(200, response);
});
});
For more details, you can look at this: mocking-http also look into this answer of SO. source
I think you should only return res inside the callback, otherwise it will return undefined since the program keeps running...
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
You may want to take a look on callback funcionality
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm trying to create a function which returns a JSON object from an URL.
It should work like this:
function getObject(url) {
// return undefined when the url or json is invalid
return object;
}
So that I can use it in this way, if I would use the following URL:
var object = getObject('http://ip.jsontest.com/');
console.log('My IP is: ' + object.ip)
The JSON from the example looks like this:
{"ip": "127.0.0.1"}
So the code above should log this:
My IP is: 127.0.0.1
I already tried it with the request module and found this example on StackOverflow:
request.get({
url: 'http://ip.jsontest.com/',
json: true,
headers: {'User-Agent': 'request'} }, (err, res, data) => {
if (err) {
console.log('Error:', err)
} else if (res.statusCode !== 200) {
console.log('Status:', res.statusCode)
} else {
// data is already parsed as JSON:
console.log(data)
}
})
The data is displayed in the console as it should, but I found no way to use the it like in the example I provided above.
Is there a way to solve this without callbacks? I read that requests are asynchronous, but I need a synchronus solution.
No there is no way to do this synchronously. You could look into using the fetch api and an async function if they're supported in your environment.
For example:
async function getMyIpAndDoSomething() {
const response = await fetch("http://ip.jsontest.com/");
const object = await response.json();
console.log(object.ip);
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I'm new to node and I'm trying to figure out the callbacks and the async nature of it.
I have this kind of function:
myObj.exampleMethod = function(req, query, profile, next) {
// sequential instructions
var greetings = "hello";
var profile = {};
var options = {
headers: {
'Content-Type': 'application/json',
},
host: 'api.github.com',
path: '/user/profile'
json: true
};
// async block
https.get(options, function(res) {
res.on('data', function(d) {
// just an example
profile.emails = [
{value: d[0].email }
];
});
}).on('error', function(e) {
console.error(e);
});
//sync operations that needs the result of the https call above
profile['who'] = "that's me"
// I should't save the profile until the async block is done
save(profile);
}
I was also trying to understand how to work with the Async library given that most of the node developers use this or a similar solution.
How can I "block" (or wait for the result) the flow of my script until I get the result from the http request? Possibly using the async library as an example
Thanks
Based on the fact that you're trying to "block" your script execution, I don't think you have a firm grasp on how async works. You should definitely read the dupe I suggested, especially this response:
How do I return the response from an asynchronous call?
To answer your question more specifically:
async.waterfall([
function(callback) {
// async block
https.get(options, function(res) {
res.on('data', function(d) {
// just an example
profile.emails = [
{value: d[0].email }
];
callback(null);
});
}).on('error', function(e) {
throw e;
});
},
function(callback) {
// I should't save the profile until the async block is done
save(profile);
callback(null);
}
]);