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

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.

Related

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.

Async function does not await

I am having a problem where an async function does not appear to be waiting. I am calling one async function from another, with the second returning a value after async operations have completed and then the first should be returning this as it has awaited it. But when logging accessToken in the first function it logs before awaiting the return from the second. Where am I going wrong? Thanks in advance.
export const confirmCode = async (verificationId, code) => {
try {
const credential = await firebase.auth.PhoneAuthProvider.credential(verificationId, code);
const accessToken = await authenticate(credential);
console.log(accessToken); // prints undefined as does not wait for above function call?
return accessToken;
} catch (error) {
console.log(error)
// this.showMessageErrorByCode(e.error.code);
}
}
const authenticate = async (credential) => {
try {
await firebase.auth().signInWithCredential(credential).then(result => {
const user = result.user;
user.getIdToken().then(accessToken => {
return accessToken;
});
})
} catch (error) {
console.log(error);
}
}
You should not mix async/await with the older version .then().
Just use it without then() like so:
export const confirmCode = async (verificationId, code) => {
try {
const credential = await firebase.auth.PhoneAuthProvider.credential(verificationId, code);
const accessToken = await authenticate(credential);
console.log(accessToken); // prints undefined as does not wait for above function call?
return accessToken;
} catch (error) {
console.log(error)
// this.showMessageErrorByCode(e.error.code);
}
}
const authenticate = async (credential) => {
try {
let result = await firebase.auth().signInWithCredential(credential); // <-- use await
const user = result.user;
accessToken = await user.getIdToken(); // <-- use await
return accessToken;
} catch (error) {
console.log(error);
}
}
For more detailed explanation, why your code does not work:
You are returning from within a .then() which is not possible
If you would want to use the old way of writing async functions, you would need to use:
return new Promise((resolve, reject) => { /* Code ... */ }); to wrap your function content
resolve(accessToken) instead of return
.then() and .catch() instead of await and try/catch
and some rejects where you can't resolve anything (so probably in the catch block)
But I would suggest you to use the async/await approach, as it is easier to read.

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.

NodeJS async/await + recursion on express request

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

Return Meteor.http results in method

I have a Meteor method that wraps around an http.get. I am trying to return the results from that http.get into the method's return so that I can use the results when I call the method.
I can't make it work though.
Here's my code:
(In shared folder)
Meteor.methods({
getWeather: function(zip) {
console.log('getting weather');
var credentials = {
client_id: "string",
client_secret: "otherstring"
}
var zipcode = zip;
var weatherUrl = "http://api.aerisapi.com/places/postalcodes/" + zipcode + "?client_id=" + credentials.client_id + "&client_secret=" + credentials.client_secret;
weather = Meteor.http.get(weatherUrl, function (error, result) {
if(error) {
console.log('http get FAILED!');
}
else {
console.log('http get SUCCES');
if (result.statusCode === 200) {
console.log('Status code = 200!');
console.log(result.content);
return result.content;
}
}
});
return weather;
}
});
For some reason, this does not return the results even though they exist and the http call works: console.log(result.content); does indeed log the results.
(Client folder)
Meteor.call('getWeather', somezipcode, function(error, results) {
if (error)
return alert(error.reason);
Session.set('weatherResults', results);
});
Of course here, the session variable ends up being empty.
(Note that this part of the code seems to be fine as it returned appropriately if I hard coded the return with some dummy string in the method.)
Help?
In your example Meteor.http.get is executed asynchronously.
See docs:
HTTP.call(method, url [, options] [, asyncCallback])
On the server, this function can be run either synchronously or
asynchronously. If the callback is omitted, it runs synchronously and
the results are returned once the request completes successfully. If
the request was not successful, an error is thrown
Switch to synchronous mode by removing asyncCallback:
try {
var result = HTTP.get( weatherUrl );
var weather = result.content;
} catch(e) {
console.log( "Cannot get weather data...", e );
}
Kuba Wyrobek is correct, but you can also still call HTTP.get asynchronously and use a future to stop the method returning until the get has responded:
var Future = Npm.require('fibers/future');
Meteor.methods({
getWeather: function(zip) {
console.log('getting weather');
var weather = new Future();
var credentials = {
client_id: "string",
client_secret: "otherstring"
}
var zipcode = zip;
var weatherUrl = "http://api.aerisapi.com/places/postalcodes/" + zipcode + "?client_id=" + credentials.client_id + "&client_secret=" + credentials.client_secret;
HTTP.get(weatherUrl, function (error, result) {
if(error) {
console.log('http get FAILED!');
weather.throw(error);
}
else {
console.log('http get SUCCES');
if (result.statusCode === 200) {
console.log('Status code = 200!');
console.log(result.content);
weather.return(result);
}
}
});
weather.wait();
}
});
There's not really much advantage to this method over a synchronous get in this case, but if you're ever doing something on the server which can benefit from something like an HTTP call running asynchronously (and thus not blocking the rest of the code in your method), but you still needs to wait for that call to return before the method can, then this is the right solution. One example would be where you need to execute multiple non-contingent gets, which would all have to wait for each other to return one by one if executed synchronously.
More here.
Sometimes asynchronous calls are preferable. You can use async/await syntax for that, and you need to promisify HTTP.get.
import { Meteor } from 'meteor/meteor';
import { HTTP } from 'meteor/http';
const httpGetAsync = (url, options) =>
new Promise((resolve, reject) => {
HTTP.get(url, options, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
Meteor.methods({
async 'test'({ url, options }) {
try {
const response = await httpGetAsync(url, options);
return response;
} catch (ex) {
throw new Meteor.Error('some-error', 'An error has happened');
}
},
});
Notice that meteor test method is marked as async. This allows using await operator inside it with method calls which return Promise. Code lines following await operators won't be executed until returned promise is resolved. In case the promise is rejected catch block will be executed.

Categories

Resources