I want to send different SMS to different people and each call to send the SMS should be synchronous, I implemented the async await for my function to work like this, but for some reason it's not working as expected.
Here's my code:
After query for qualified users,
if(userQualifies) {
try{
await insertIntoTable();
} catch(err) {
console.log(err);
}
}
async function insertIntoTable(){
try{
await db.any(QUERY TO INSERT)
.then(async function(idCreated){
try{
var params = {
'messagingServiceSid': 'XXXXXXXXXX',
'to': ['1' + phone],
'body': message,
}
await sendMessage(params);
}catch(error){
console.log(error);
}
})
} catch(err){
console.log(err);
}
}
async function sendMessage(params) {
console.log('Im on sendMessage');
return client.messages.create(params)
.then( msg => {
console.log("SUCCESS:");
})
.catch(err => {
console.log("ERROR:");
});
console.log("message sent");
return 'done';
}
when I run this, I get the log of Im on sendMessage after inserting into the table but it doesn's send the message, it's ignoring the return of the sendMessage() function and sends all of the messages at the end at the same time.
Am I missing something to make it send the message when it goes from insertIntoTable() to sendMessage()
I'm not really sure what most of your code is doing, but here's the async pattern for waiting for one thing in an array to finish its async action before starting the next one:
async function sendMessage(params) {
console.log('Im on sendMessage');
return client.messages.create(params)
.then( msg => {
console.log("SUCCESS:");
})
.catch(err => {
console.log("ERROR:");
});
}
const messages = [{
'messagingServiceSid': 'XXXXXXXXXX',
'to': ['1000000'],
'body': 'first message',
},{
'messagingServiceSid': 'XXXXXXXXXX',
'to': ['2000000'],
'body': 'second message',
},
{
'messagingServiceSid': 'XXXXXXXXXX',
'to': ['3000000'],
'body': 'third message',
}];
async function setMultipleMessages(messages) {
for (let message of messages) {
await sendMessage(message);
}
}
setMultipleMessages(messages);
Related
I want to make a call to my backend (registerSanctumFacebook method) after a facebook Graph request to get user profile info (email), however I'm getting the following error:
await is only allowed within async functions
Pretty self explanatory, the problem is, I don't know how to make graph start method to work with async-await...
const getInfoFromToken = async (token) => {
const PROFILE_REQUEST_PARAMS = {
fields: {
string: 'email',
},
};
const profileRequest = new GraphRequest(
'/me',
{token, parameters: PROFILE_REQUEST_PARAMS},
(error, user) => {
if (error) {
console.log('login info has error: ' + error);
} else {
//this.setState({userInfo: user});
console.log('user:', user);
}
},
);
new GraphRequestManager().addRequest(profileRequest).start();
let response = await registerSanctumFacebook(user.email,user.id);
};
How I call getTokenInfo method:
const loginWithFacebook = async () => {
LoginManager.logInWithPermissions(['email']).then(
login => {
if (login.isCancelled) {
console.log('Login cancelled');
} else {
AccessToken.getCurrentAccessToken().then(data => {
const accessToken = data.accessToken.toString();
console.log('accessToken',accessToken);
getInfoFromToken(accessToken);
});
}
},
error => {
console.log('Login fail with error: ' + error);
},
);
};
As per your problem statement, I think you should add await on this line
await new GraphRequestManager().addRequest(profileRequest).start();
await will only work if the function after await keyword is also async.
or declare registerSanctumFacebook as async
I had an issue where I needed to return the response of an async function which kept being returned as undefined. So I decided to use setTimeout() before trying to use it. It still doesn't seem to work. Can someone explain why?
My attempt:
insertUser = (req,res) => {
var record = {
'handle': req.body.handle,
'name': req.body.name,
'password': req.body.password
};
var response;
createUser(record, response)
setTimeout(() => {
console.log(response);
},10000)
};
createUser = (record, response) => {
users.insertOne(record, function(err, result){
if(err){
response = {'code': 404, 'message': 'Something went wrong. Message: ', err}
}else{
response = {'code': 200, 'message': result.insertedId}
}
})
setTimeout(() => {
console.log(response)
}, 1000);
};
The problem is that users.insertOne doesn't run synchronously, and the function createUser returns before that, hence you are getting undefined as a return value.
There are a couple of ways you can solve this -
=> Using async/await
const createUser = async (record, response) => {
try {
const result = await users.insertOne(record);
response = {
'code': 200,
'message': result.insertedId
}
} catch (err) {
response = {
'code': 404,
'message': 'Something went wrong. Message: ',
err
}
})
return response;
};
const insertUser = async (req,res) => {
let record = {
'handle': req.body.handle,
'name': req.body.name,
'password': req.body.password
};
let response;
response = await createUser(record, response);
console.log(response);
};
=> Using plain promises
const createUser = (record) => {
return new Promise((resolve, reject) => {
users.insertOne(record, function(err, result) {
if (err) {
// Or use `reject` if you want to have this in .catch callback
resolve({
'code': 404,
'message': 'Something went wrong. Message: ',
err
});
} else {
resolve({
'code': 200,
'message': result.insertedId
});
}
})
})
};
const insertUser = (req, res) => {
const record = {
'handle': req.body.handle,
'name': req.body.name,
'password': req.body.password
};
let response;
createUser(record).then((res) => {
response = res;
console.log(response);
});
};
I'm a React and Socket.io newbie. My async function below is not executing. My socket emit is working correctly because "message received" is being console logged. However, nothing else is.
socket.on('connected', function(data) {
//load all messages
console.log('message received');
(async () => {
try {
console.log('searching for Schema');
const conversation = await Conversation.find({roomId: data.roomid}).populate('messages').lean().exec();
const mess = conversation.map();
console.log('Schema found');
}
catch (error) {
console.log('Schema being created');
Conversation.create({type: data.roomid});
}
});
});
Just execute your function, adding "()" at the end:
socket.on('connected', function(data) {
//load all messages
console.log('message received');
(async () => {
try {
console.log('searching for Schema');
const conversation = await Conversation.find({roomId: data.roomid}).populate('messages').lean().exec();
const mess = conversation.map();
console.log('Schema found');
}
catch (error) {
console.log('Schema being created');
Conversation.create({type: data.roomid});
}
})(); // <- just this
});
I recommend to you create a function separately, will looks better and clear.
You are not actually calling the async method, just defining it and moving on.
Try this:
const searchForSchema = async (data) => {
try {
console.log('searching for Schema');
const conversation = await Conversation.find({roomId: data.roomid}).populate('messages').lean().exec();
const mess = conversation.map();
console.log('Schema found');
}
catch (error) {
console.log('Schema being created');
Conversation.create({type: data.roomid});
}
}
socket.on('connected', (data) => {
//load all messages
console.log('message received');
await searchForSchema(data);
});
Having issues with using async and await. I'm executing two queries and then saving the result to a temp variable. After I have collected the response from all executed queries, I'm going to send that to the client.
Here is my current example code.
module.exports = (app) => {
app.get('/api/stats', (req, res) => {
let fetch1 = '';
let fetch2 = '';
conn.query('query here', [], async (error, results) => {
if (error) {
return res.send({
success: false,
message: 'There was an error.'
});
} else {
fetch1 = results;
}
});
conn.query('query here', [], async (error, results) => {
if (error) {
return res.send({
success: false,
message: 'There was an error.'
});
} else {
fetch2 = results;
}
});
// I need to wait until the queries have resolved so that I can send the correct data
return res.send({
success: true,
fetch1: fetch1,
fetch2: fetch2
});
});
};
I basically need to wait until the queries have been resolved so that I can send the correct data towards the end.
Can anyone explain how I can use await and async to accomplish this?
Thanks.
You can only await a Promise, so for functions that don't return Promises you need to create a Promise wrapper. This needs to be done per call that would previously use a callback, but you can make a helper function per function you need to wrap.
function queryPromise(query, parameters) {
return new Promise((resolve, reject) => {
conn.query(query, parameters, (err, results) => {
if(err) {
reject(err);
} else {
resolve(results);
}
});
});
}
module.exports = (app) => {
app.get('/api/stats', async (req, res) => {
try {
let fetch1 = await queryPromise('query here', []);
let fetch2 = await queryPromise('query here', []);
res.send({
success: true,
fetch1: fetch1,
fetch2: fetch2
});
} catch {
res.send({
success: false,
message: 'There was an error.'
});
}
});
};
From my knowledge, I usually apply async to functions and perform await on certain variables (inside the function) that need to be acquired from a specific database.
So to implement this into your function containing the async tag, you could possibly do:
fetch1 = await results;
fetch2 = await results;
This will wait until the data is attached onto the variable fetch1 and fetch2 before continuing on with the code.
Sorry if this was very vague, hopefully this was somewhat helpful.
I am using nodemailer to send emails through my node app. Sometimes Email does not work and throws an error until I try twice or thrice. I want my program to try again and again until the mail is successfully sent.
Here's my code:
const mailOptions = {
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
res.status(500).json({
message: "Mail not sent",
error
});
} else {
res.status(200).json({message: "Mail Sent", response: info.response});
}
});
How can I use the same function inside my if block?
Wrap sendMail in a function that returns a Promise
const promiseWrapper = mailOptions => new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
reject(error);
return;
}
resolve(info);
});
then in your route make the handler an async function and loop how many time that you want, then check if info exists if it does send 200 if not send 500
app.post('/sendmail', async (req, res) => {
let info;
let error;
for (let i = 0; i < 3; i++) {
try {
info = await promiseWrapper(mailOptions);
break;
} catch (e) {
error = e;
}
}
info
? res.status(200).json({ message: "Mail Sent", response: info.response })
: res.status(500).json({ message: "Mail not send", error }));
});
You can first separate the retry logic in a different file, so you can use it in various places.
Newer versions of nodemailer support promises for transporter.sendMail
// retry.js
// retries a function, called asynchronously, n amount of times
export async function retry(fn, n) {
for (let i = 0; i < n; i++) {
try {
return await fn()
} catch (err) {
console.log(err)
}
}
}
And pass the transporter function to the retry logic, with the amount of times you want to retry (in this example: 3)
import {retry} from '../utils/retry'
// ...
app.post('/sendmail', async (req, res) => {
try {
retry(
() =>
transporter.sendMail({
// your configuration
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
}),
3 // max retries
)
} catch (err) {
console.log(err)
// failed max retry times
res.sendStatus(500)
}
res.sendStatus(200)
})
const mailOptions = {
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
};
var i;
for(i = 0; i <= 1; i++) {
transporter.sendMail(mailOptions, function(error, info){
if (error) {
res.status(500).json({
message: "Mail not sent",
error
});
i = 0;
} else {
i = 2;
res.status(200).json({message: "Mail Sent", response: info.response});
}
});
}
Try the code above will run the function again and again if the error occur and it will exit the loop if no error occur.
Wrap it into a function and call in this way:
const mailOptions = {
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
};
function sendMail(mailOptions) {
transporter.sendMail(mailOptions, function(error, info){
if (error) {
return sendMail(mailOptions)
} else {
return res.status(200).json({message: "Mail Sent", response: info.response});
}
});
}
return sendMail(mailOptions);