Nodejs wait till async function completes and print the results - javascript

I want to wait on the HTTP POST request to complete and then return response to the caller function. I am getting Undefined when I print the received results.
I have defined post method as below:
// httpFile.js
const axios = require('axios');
module.exports = {
getPostResult: async function(params) {
console.log("getPostResult async called...");
var result = await axios.post("https://post.some.url", params)
.then ((response) => {
console.log("getPostResult async success");
return {response.data.param};
})
.catch ((error) => {
console.log("getPostResult async failed");
return {error.response.data.param};
});
}
}
And I am calling it in this way:
// someFile.js
const httpFile = require('./httpFile');
// Called on some ext. event
async function getPostResult() {
var params = {var: 1};
var result = await httpFile.getPostResult(params);
// Getting Undefined
console.log("Done Result: " + JSON.stringify(result));
}
I don't want to handle the .then and .catch in the calling function as I want to return the different values based on the POST result.
How should I wait for the response and get the return results.
In the above code I am getting the log statements as expected and "Done Result" get printed at the very end after the 'getPostResult' returns.

you are using both await & .then thats why it returns undefined.
this is how it should look
// httpFile.js
const axios = require('axios')
module.exports = {
getPostResult: async function (params) {
try {
const res = await axios.post('https://post.some.url', params)
return res.data
} catch (error) {
// I wouldn't recommend catching error,
// since there is no way to distinguish between response & error
return error.response.data
}
},
}
if you want to catch error outside of this function then this is way to go.
getPostResult: async function (params) {
const res = await axios.post('https://post.some.url', params)
return res.data
},

Related

stored array outside of async function in nodejs fetch

How do I get the value of the failed array outside of the function? Because I need this array as an input for other functions.
failed = [];
async function fetchFromApi(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
console.log(failed)
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
};
fetchFromApi("abc")
console.log(failed)
The console.log("failed") in the code above gives me an empty array []. I want it to be getting ["abc"] when this variable being called outside of the function
UPDATE EDIT (new follow-up question):
I tried #SlothOverlord 's solution and it seems to work below is the example.
const myFunction = async (j) => {
failed = [];
async function fetchFromApi(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
};
await fetchFromApi(j)
return failed
}
myFunction("abc").then(data=>console.log(failed))
However, when I add in a forEach statement within the function, it breaks and returns an empty array again. See example below. What's going on here?
const myFunction = async (j) => {
failed = [];
async function fetchFromApi(arrays) {
arrays.forEach(async function(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
// console.log(failed)
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
});
}
await fetchFromApi(j)
// console.log(failed)
return failed
}
myFunction(["aaa", "abc"]).then(data=>console.log(failed))
You need to await the fetchFromApi("abc") function.
Async await only works INSIDE the function, not outside of it.
So what happened is:
fetchFromApi("abc") is called
console.log(failed) is empty
fetchFromApi("abc") finished
The solution is to wrap the function in async and await the fetchFromApi call
const myFunction = async () => {
//...
failed = [];
async function fetchFromApi(i) {
//...
}
await fetchFromApi("abc")
console.log(failed)
}
fetchFromApi is an async method, you need to await it if you want to see it's result logged.
JavaScript has a concurrency model based on an event loop, which is responsible for executing the code, collecting and processing events. when the async call will have it's result it will be placed in the callback queue and on the next iteration (tick), it will be popped out from there and placed in the execution stack to be processed. when you use await, the exection call will be halted at that point and will progress until the async call has it's result.
failed = [];
async function fetchFromApi(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
console.log(failed)
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
};
await fetchFromApi("abc")
console.log(failed)
JS event loop - https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

Wait for response from request before returning

I am trying to create a function with a GET request that returns a portion of the data from the GET request. However, it keeps returning before the data is retrieved, so I keep getting "undefined". How can I set this up so it actually waits for the data to be set before returning?
let getInfo = async () => {
const request = net.request({
url: URL
})
return new Promise((resolve, reject) => { // Promise being here DOES work
request.on('response', (response) => {
response.on('data', (chunk) => {
//return new Promise((resolve, reject) => { //Promise being here does NOT work
let body = JSON.parse(chunk)
let info = body.data
if (info){
resolve(info);
}
reject();
//})
});
});
request.write('')
request.end()
}).then(data => {
console.log("From then: "+data)
return data
})
}
getInfo().then(data => {
console.log("From outside: "+data)
})
Edit: This is the updated version that still does not work. I am trying to use the native electron method and I don't see why this doesn't work. The "From then:" part displays the info correctly. But when run "From outside:" it prints undefined. Does the issue have anything to do with the response.on being nested inside the request.on?
Solution: As #NidhinDavid showed in his answer, the issue was that the promise was inside the 'response' listener. Moving the 'GET' request from start to finish inside the Promise fixed it to giving the correct output. I have updated my code to reflect that for future individuals.
let getInfo = () => {
let info;
const request = net.request({
url: URL
})
return new Promise((resolve, reject) => {
request.on('response', (response) => {
response.on('data', (chunk) => {
request.write('')
request.end()
let body = JSON.parse(chunk)
info = body.data
if (info) {
resolve(info)
} else {
reject('Something went wrong');
}
});
});
})
}
getInfo()
.then(data => {
// this will be your info object
console.log(data)
})
.catch(err => {
// this will log 'Something went wrong' in case of any error
console.log(err)
})
You need to return inside your, on type event handler. Read more about asynchronous code and synchronous code here
I couldn't find the net module and the one which is included with Nodejs do not have request method. So to get the similar concept of event emiters and promise I am using http module and doing a http request to fetch json and parse it
'use strict'
var https = require('https');
const getInfo = async () => {
// create a new promise chain
// remember it is a chain, if one return is omitted
// then the chain is broken
return new Promise((resolve, reject) => {
var options = {
host: 'support.oneskyapp.com',
path: '/hc/en-us/article_attachments/202761727/example_2.json'
};
// start the request
https.request(options, function (response) {
var str = '';
// data arrives in chunks
// chunks needs to be stitched together before parsing
response.on('data', function (chunk) {
str += chunk;
});
// response body obtained
// resolve (aka return) the result
// or parse it, or do whatever you want with it
response.on('end', function () {
resolve(str)
});
// errors are another event
// listen for errors and reject when they are encountered
response.on('error', function (err) {
reject(err)
})
}).end()
})
}
//*********************************************
// using async await
//*********************************************
// if this is the entry point into app
// then top-level async approach required
(async ()=>{
try{
let data = await getInfo()
console.log("From ASYNC AWAIT ")
console.log(JSON.stringify(JSON.parse(data)))
}
catch (err) {
console.log("operation failed, error: ", err)
}
})();
//************************************************
// using promise chains
//************************************************
getInfo()
.then((data)=>{
console.log("FROM PROMISE CHAIN ")
console.log(JSON.stringify(JSON.parse(data)))
})
.catch((err)=>{
console.log("operation failed, error: ", err)
})
Tyr this, it might works for you,
let info;
const getInfo = async (_url)=>{
const response = await fetch(_url);
const data = await response.json();
info = data;
} ;
const url = "some url";
getInfo(url);
console.log(info);
Async function always returns a promise, so either consume that promise or internally await the data and assign it to some variable.
Check for the valid data required in info by logging it to the console.

Unable to receive/send response from a Promise in Lambda function

I am having a Lambda function, in which I am taking a parameter from Query String and using it to call a downstream service that will inturn return a promise. I am unable to send back the response received by the Promise.
This is my Lambda function:
export const handler = async (event) => {
let sessionId = event.queryStringParameters.sessionId;
const testClient = new Client.WebStoreClient(config);
const sessionResponse = getSession(testClient, sessionId);
sessionResponse.then(function (result) {
console.log(result);
});
const response = {
statusCode: 200,
body: JSON.stringify(sessionResponse),
};
return response;
};
async function getSession(testClient, sessionId) {
let data = await testClient.getSession(sessionId, headers)
.then((response) => response.body);
return data;
}
When I am executing this, I am getting a null response: { statusCode: 200, body: '{}' } from the Lambda function output. I tried to console log the value that I have gotten and was receiving this: Promise { <pending> }
I am suspecting this to be a Javascript/Typescript Promise issue which I am slightly neglecting. Any help is appreciated here. Thanks in advance.
In your response, you are trying to stringify the promise instead of the promise value and it gives you an empty object as a String.
You can try it:
JSON.stringify(Promise.resolve(1)) // output is "{}"
You can only access the value of a Promise from inside the callback you pass to then.
Think of it this way: inside of then is the future, the surrounding code is the present. You can't reference future data in the present.
You probably wanted to write
return sessionResponse.then(function (result) {
return {
statusCode: 200,
body: JSON.stringify(result),
}
});
The above returns a promise containing your response.
You could have also just written getSession this way
function getSession(testClient, sessionId) {
return testClient.getSession(sessionId, headers)
.then((response) => response.body);
}
I suggest that you practice using promises without async/await
An alternative to geoffrey's answer, note that both of your functions are async, meaning you can use the same await keyword you used in getSession().
export const handler = async (event) => {
// ...
const sessionResponse = await getSession(testClient, sessionId);
// ^
console.log(sessionResponse);
const response = {
statusCode: 200,
body: JSON.stringify(sessionResponse),
};
return response;
};
async function getSession(testClient, sessionId) {
let data = await testClient.getSession(sessionId, headers)
.then((response) => response.body);
return data;
}
This is roughly the equivalent of...
export const handler = (event) => {
// ...
return getSession(testClient, sessionId).then((data) => {
console.log(data);
const response = {
statusCode: 200,
body: JSON.stringify(sessionResponse),
};
return response;
});
};
function getSession(testClient, sessionId) {
return testClient
.getSession(sessionId, headers)
.then((response) => response.body);
}
Note that your getSession() function is returning a Promise by virtue of async (and in the translated example above). Your handler() function is likewise returning a Promise, so whatever is calling it will need to use a .then() or be async itself to leverage an await. As you can see this asynchronous requirement cascades.

Make axios call from another axios promise and save returned data

I am making an axios call from promise of another axios call, the code looks like below, the call is basically from the first method to the second method.
UPDATED CODE BASED ON SUGGESTION
It simply says: Can not use keyword 'await' outside an async function then I tried
var data = async () => {
await this.checkParentLoggerLevel();
};
still did not work
async updateLevel(logger, level, index) {
alert(index);
axios
.post(
'url'
)
.then(() => {
var data = await this.checkParentLoggerLevel();
alert('waiting');
alert(
'This will be executed before the second methods returns HEllo'
);
alert(data);
});
},
Second method:
async checkParentLoggerLevel() {
alert('inside checkParentLoggerLevel ');
return await axios
.get('url')
.then(() => {
alert('returning hello');
return 'hello';
});
},
My aim to to save the returned hello to data variable in first method.This is not working. The other problem is after the this.checkParentLoggerLevel() methods call code execution continues and does not wait for the retuned value.
This happens because inside checkParentLoggerLevel you are not waiting for the axios promise to complete. You can do it like:
async checkParentLoggerLevel() {
alert('inside checkParentLoggerLevel ');
return await axios
.get('url')
.then((res) => {
return 'hello';
});
}
Also, you need to await inside updateLevel like:
async updateLevel() {
axios
.post(url)
.then(async (res) => {
var data = await this.checkParentLoggerLevel();
alert("This will be executed before the second methods returns HEllo");
alert(data);
});
}
You should chain the promises, so:
updateLevel() {
axios
.post(url)
.then(res => {
return this.checkParentLoggerLevel.then(data => ([res, data]);
})
.then(([res, data]) => {
// here
});
}
Or simply with async await:
async updateLevel() {
const res = await axios.post(url);
const data = await this.checkParentLoggerLevel();
// Do whatever you want
}

Save Async/Await response on a variable

I am trying to understand async calls using async/await and try/catch.
In the example below, how can I save my successful response to a variable that can be utilized throughout the rest of the code?
const axios = require('axios');
const users = 'http://localhost:3000/users';
const asyncExample = async () =>{
try {
const data = await axios(users);
console.log(data); //200
}
catch (err) {
console.log(err);
}
};
//Save response on a variable
const globalData = asyncExample();
console.log(globalData) //Promise { <pending> }
1) Return something from your asyncExample function
const asyncExample = async () => {
const result = await axios(users)
return result
}
2) Call that function and handle its returned Promise:
;(async () => {
const users = await asyncExample()
console.log(users)
})()
Here's why should you handle it like this:
You can't do top-level await (there's a proposal for it though);
await must exist within an async function.
However I must point out that your original example doesn't need async/await
at all; Since axios already returns a Promise you can simply do:
const asyncExample = () => {
return axios(users)
}
const users = await asyncExample()
try..catch creates a new block scope. Use let to define data before try..catch instead of const, return data from asyncExample function call
(async() => {
const users = 123;
const asyncExample = async() => {
let data;
try {
data = await Promise.resolve(users);
} catch (err) {
console.log(err);
}
return data;
};
//Save response on a variable
const globalData = await asyncExample();
console.log(globalData);
// return globalData;
})();
I had same issue with you and found this post. After 2 days of trying I finally found a simple solution.
According to the document of JS, an async function will only return a Promise object instead of value. To access the response of Promise, you have to use .then()method or await which can return the resulting object of Promise is instead of Promise itself.
To change variables from await, you have access and change the variable you want to assign within the async function instead of return from it.
//Save response on a variable
var globalData;
const asyncExample = async () =>{
try {
const data = await axios(users);
globalData = data; // this will change globalData
console.log(data); //200
}
catch (err) {
console.log(err);
}
};
asyncExample();
But if you do this, you may get an undefined output.
asyncExample();
console.log(globalData) //undefined
Since asyncExample() is an async function, when console.log is called, asyncExample() has not finished yet, so globalData is still not assigned. The following code will call console.log after asyncExample() was done.
const show = async () => {
await asyncExample();
console.log(globalData);
}
show();
Because the events are happening asynchronously you need to tie in a callback/promise. I'm going to assume it returns a promise.
const axios = require('axios');
const users = 'http://localhost:3000/users';
const asyncExample = async () =>{
try {
const data = await axios(users);
console.log(data); //200
}
catch (err) {
console.log(err);
}
};
//Save response on a variable
const globalData = asyncExample().then( (success, err) => {
if (err) { console.error(err); }
console.log(success)
}
Just use a callback/promise (cascading programming):
axios(users).then(function(response) {
const globalData = response;
console.log(globalData)
});

Categories

Resources