NodeJS async/await + recursion on express request - javascript

I have a function called GetAllData() that calls GetPurchaseData, which recursively calls itself until it loads all the data. In
async function GetAllData(){
console.log("starting loading purchase data");
await GetPurchaseData();
console.log("purchase data loaded")
}
async function GetPurchaseData(){
return new Promise(async function (resolve,reject){
var Headers = {
....
}
await request({url: xxx, headers: Headers },async function(error, response, body) {
var tmp = JSON.parse(body)
_.forEach(tmp.Purchases, p => purchaseData.push(p));
if (response.headers.pagination){
return await GetPurchasePaginatedData()
}
else{
console.log("done loading....")
return resolve("done")
}
});
})
}
Node JS prints the following output:
starting loading purchase data
done loading....
but it never comes back up to GetAllData to print
purchase data loaded
it almost seems like its stuck in function, but my opinion is that somehow the line of "return resolve("done")" does not get back up to the initial call to actually mark the Promise as complete.

Avoid the async/await Promise constructor antipattern (see also here), and avoid passing an async function as a regular callback - you need to use the Promise constructor to promisify an existing callback API!
async function GetPurchaseData() {
var headers = {…};
var promise = new Promise((resolve,reject) => { // not async!
request({url: xxx, headers}, (error, response, body) => { // not async!
if (error) reject(error);
else resolve({response, body});
});
}); // that's it!
var {response, body} = await promise;
for (var p of JSON.parse(body).Purchases)
purchaseData.push(p));
if (response.headers.pagination) {
return GetPurchasePaginatedData()
} else {
console.log("done loading....")
return "done";
}
}

I don't have much experience with async/await, but from what I've read, shouldn't the code look something like this.
async function GetAllData(){
console.log("starting loading purchase data");
await GetPurchaseData();
console.log("purchase data loaded")
}
async function GetPurchaseData(){
let body = await request({url: xxx, headers: Headers })
var tmp = JSON.parse(body)
_.forEach(tmp.Purchases, p => purchaseData.push(p));
if (response.headers.pagination){
return await GetPurchasePaginatedData()
}
else{
console.log("done loading....")
return "done"
}
}

Related

Nodejs wait till async function completes and print the results

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
},

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.

resolve and reject issue using node js

Is this possible way to return resolve or reject message from one function to another?
As I am writing to pass resolve message in postman whenever my task is completed or reject message when there is some error
But after after writing return it still not returning the resolve message or reject message inside Postman
any idea how this can be resolve?
async function readFile(filePath) {}
async function getAllFile(filePath) {
const paths = await readFile(filePath);
}
async function filterFiles(filePath) {
const paths = await getAllFile(filePath);
}
function addDocument(childProduct){
return new Promise((resolve, reject) => {
Document.create({
name: childProduct,
},
}).then(function (filePath) {
filterFiles(filePath);
let msg = "Document created Succesfully";
return resolve(msg);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
});
}
function updateDoc(data){
return new Promise((resolve, reject) => {
Document.update({
name: data.name,
}
where: {
product_id: data,
},
})
}).then(function (childProduct) {
addDocument(childProduct);
let msg = "Updated Successfully";
return resolve(msg);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
}
Product.findOne and Document.findAll return a Promise, so they can be returned and awaited directly.
You can chain await func1(); await func2(); await func3() in one try{} block, and catch any error that happens in one place :
const filterFiles = async filePath => {
const paths = await getAllFiles(filePath);
// .. Do something else here
return paths // This is a Promise because async functions always return a Promise
}
const findOneDoc = name => Product.findOne({ where: { name } }); // This func returns a Promise
const findAllDocs = product_id => Document.findAll({ // This func returns a Promise too
raw: true,
where: { product_id }
});
(async () => {
try {
const childProduct = await findOneDoc("some_name");
console.log("All good until now!");
const filePath = await findAllDocs(childProduct._id);
console.log("Still good");
const filteredFiles = await filterFiles(filePath);
console.log("All went well.");
console.log(filteredFiles);
} catch (err) {
// If any of the functions above fails, the try{} block will break and the error will be caught here.
console.log(`Error!`, err);
}
})();
There are few things I would like to mention.
When you create a promise, it should have resolve() and reject() inside it.
for ex-
function testPromise() {
return new Promise((resolve, reject) => {
// your logic
// The followin if-else is not nessesary, its just for an illustration
if (Success condition met) {
resolve(object you want to return);
}else {
reject(error);
// you can add error message in this error as well
}
});
}
// Calling the method with await
let obj = await testPromise()
// OR call with then, but its better to go with await
testPromise().then((obj)=>{
// Access obj here
})
In the method which you have written, You have applied .then() method to non promise object. You have to complete the promise block first with resolve() and reject() inside it. Then you can return that promise from a function, use it in async function Or apply .then() block on it.
Also you don't need to add return statement to resolve() and reject() statement. The system will take care of it.
You can also use try catch block inside a promise. Its better to write reject() statement in catch block, if anything goes wrong.

JavaScript(node.js) - async await does not work

I have some problems using async/await. If i call getAccountDetails i only get undefined and afterwards i get the log
getOpengraphResponse is ok
But i use async/await. And request is request-promise-native. At position one should be the log
getOpengraphResponse is ok
and then the property details should be displayed. Where is my mistake?
const https = require('https');
const request = require('request-promise-native');
let openGraphBaseURL = "https://graph.facebook.com//v3.1/";
class Account{
constructor(name){
this.name = name;
}
}
class InstagramAccount extends Account{
async getAccountDetails(EdgeID, token){
this.EdgeID = EdgeID;
this.token = "&access_token=" + token;
this.command = this.EdgeID+"?fields=name,username,website,biography,followers_count,follows_count,media_count,profile_picture_url"+this.token;
this.details = await this.getOpengraphResponse(this.command);
console.log(this.details);
}
getOpengraphResponse(command){
request.get({
url: openGraphBaseURL+command,
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 {
console.log('getOpengraphResponse is ok');
return data;
}
});
}
}
async/await can implemented with promises. i.e
var function_name = function(){
// Create a instance of promise and return it.
return new Promise(function(resolve,reject){
// this part enclose some long processing tasks
//if reject() or resolve()
//else reject() or resolve()
});
}
//function which contains await must started with async
async function(){
// you need to enclose the await in try/catch if you have reject statement
try{
await function_name(); // resolve() is handled here.
console.log('this will execute only after resolve statement execution');
}catch(err){
// reject() is handled here.
console.log('this will execute only after reject statement execution');
}
}
You can also use then/catch instead of try/catch.
You can only (usefully) await a promise.
getOpengraphResponse doesn't return a promise. It has no return statement at all, so it returns undefined.
You'll need to treat the return value of request.get as a promise. Don't pass it a callback. Do use then or await.
Return either the value you want (if you await inside getOpengraphResponse) or the return value of request.get.

async await not working properly

I am new to JavasSript's async, await and promise features.
What I am doing is,
async function sendTextMessage(text) {
console.log("----1----");
var messageData = {
message: {
text: text
}
};
await callSendAPI(messageData);
}
async function sendImageMessage(imageUrl) {
console.log("----2----");
var messageData = {
message: {
url: imageUrl
}
};
await callSendAPI(messageData);
}
async function sendQuickReply(replies) {
console.log("----3----");
var messageData = {
message: {
text: text,
quick_replies: replies
}
};
await callSendAPI(messageData);
}
async function callSendAPI(messageData) {
await request({
uri: 'https://graph.facebook.com/v2.6/me/messages',
qs: {
access_token: config.FB_PAGE_TOKEN
},
method: 'POST',
json: messageData
}, function(error, response, body) {
if (!error && response.statusCode == 200) {
var recipientId = body.recipient_id;
var messageId = body.message_id;
if (messageId) {
console.log("Successfully sent message with id %s to recipient %s",
messageId, recipientId);
} else {
console.log("Successfully called Send API for recipient %s",
recipientId);
}
} else {
console.error("Failed calling Send API", response.statusCode, response.statusMessage, body.error);
}
});
}
I am calling this functions in one switch case like,
async function send(){
await sendTextMessage(text);
await sendImageMessage(img);
await sendQuickReply(replies)
}
send()
But while response showssendImageMessage() last because this function may be not getting ready when I am sending imageUrl to generate a response.
Note this answer was written against the original question and not later edits made by the OP.
An async function is asynchronous. Other functions will not wait for it.
So you call sendTextMessage which calls callSendAPI and then the rest of the program carries on.
callSendAPI runs asynchronously. It calls request and waits for the promise returned by request to be resolved. When it has resolved, callSendAPI picks up the return value of request (well, it would if you captured the return value) and then continues with the next line (only there isn't a next line).
async / await do not make asynchronous code synchronous. They just make it look like it in inside the function declared as async which, itself, becomes asynchronous.
You could put your three function calls in an async function of their own, make sure each one returns a Promise, and then call each of those three with await.
See also How do I return the response from an asynchronous call?.
I hope that all you want todo is process some operations in strict order.
This is why async and await in ES6 exists.
So by example it may be like this do A then do B then do C or A > B > C
As you can see the last method do3 has only 500 ms delay but it is executed as last and not as first one.
Without async and await operators it would be executed as first function and this is default behavior of JavaScript execution. Broser will execute sync code as first and async after. But not with async and await anymore :)
You should also know that if you prefix string, number of function with await then the will be transformed into promise automatically.
The console will print :
'juraj1'
'juraj2'
'juraj3'
here is simple example :
function do1() {
return new Promise(resolve => {
return setTimeout(() => resolve("juraj1"), 3000);
});
}
function do2() {
return new Promise(resolve => {
return setTimeout(() => resolve("juraj2"), 2000);
});
}
function do3() {
return new Promise(resolve => {
return setTimeout(() => resolve("juraj3"), 500);
});
}
async function ForceAsynTOBeSync() {
const a = await do1();
console.log(a);
const b = await do2();
console.log(b);
const c = await do3();
console.log(c);
}
ForceAsynTOBeSync();
You have to await the API calls:
await callSendAPI(messageData);
And therefore the functions these calls are in need to be async too and awaited when called and so on.

Categories

Resources