Async function returns pending promise node js - node.js

This is a very easy question but no google search results return the correct answer.
const express = require("express");
const app = express();
const cors = require("cors");
const pool = require("./db");
const poolec2 = require("./db");
require("./function")();
returnMappings = async function(connection){
try {
let mapping = await connection.query("SELECT ticker FROM mappings");
let results = await mapping.rows;
//console.log(results);
return results;
} catch (err) {
console.error(err.message);
}
};
const mappings = returnMappings(poolec2);
console.log(mappings);
What am I missing here that is not returning my data? When I unquote console.log(results); I can see the desired results in my terminal. I've tried various versions of using .then but have not had any success return results.then;, const mappings = returnMappings(poolec2).then;, console.log(mappings.then);. I've also tried returning my results outside of my try catch with no luck. I'm really stuck trying to understand how I go about returning a from an async function.
EDIT
The goal is to pass the results from the above async function to another function to check if the a user inputted value exists in that vector of mappings. So indexOf based on a user input, I then use if else to return true or false. With the final results being either true or false.
checkMappings = function(string,input){
stringArray = string;
value = stringArray.indexOf(input);
if(value > -1){
return false
}else{
return true
}
};
SOLUTION
returnMappings = async function(connection,input){
try {
const mapping = await connection.query("SELECT ticker FROM mappings_production");
const results = await mapping.rows;
//console.log(results);
return results;
} catch (err) {
console.error(err.message);
}
};
checkMappings = function(string,input){
let stringArray = JSON.stringify(string);
let value = stringArrayC1.indexOf(input);
function test(a) {
let check;
if(a > -1) {
return true
}else {
return false
}
};
console.log(test(value));
return test(value);
};
const resMappingCheck = returnMappings(poolec2).then((mappings) => checkMappings(mappings,"AAPL"));
console.log(resMappingCheck);
this worked for what I needed to do

As others have pointed out, await can only be used in an async function, but using .then() is functionally equivalent.
This syntax that should work for you:
returnMappings(poolec2).then((mappings) => console.log(mappings));
if you want to do something more elaborate / multi-line, you can use curly braces like so:
returnMappings(poolec2).then((mappings) => {
console.log(mappings)
});
UPDATE:
If you want to chain two functions together, then you'll need to start with the .then() pattern: you can declare the callback function in .then() to be asynchronous. At that point, you can start to use await like you're used to.
I'm not sure what relationship you're trying to create between returnMappings() and checkMappings(), but you can chain them together like this: (note the use of async on the first line to allow the use of await inside the callback.)
returnMappings('test').then(async (mapping) => {
const checkResult = await checkMappings(mapping)
console.log(`checkMapping result: ${checkResult}`)
}).catch((err) => console.log(`Error: ${err}`))

Try this:
const mappings = await returnMappings(poolec2);
That will work if you wrap the code inside an async function. Or you could do:
let mappings;
returnMappings(poolec2).then(res => {
mappings = res;
});

Related

Async/await function is returning "undefined" instead of expected String value

I am trying to learn how to work with async functions. I have my code below. There are two functions. The first, apiAddTask, calls the second function SchedulesDAO.GetScheduleByTitle. Both functions are static async functions and 'await' is used when calling the GetScheduleByTitle function.
In the GetScheduleByTitle function, I grab the needed ID from a Mongo Database. The function is correctly grabbing the ID, but is not returning it. Instead it returns undefined.
apiAddTask function:
static async apiAddTask(req, res, next){
try{
let taskFrequency = null
const taskTitle = req.body.title
const taskRepeat = req.body.repeat
if (taskRepeat == true){
taskFrequency = req.body.frequency
}
const taskStart = req.body.startdate
const taskEnd = req.body.enddate
let taskSchedule = await SchedulesDAO.GetScheduleByTitle(req.body.schedule) //CALL TO GETSCHEDULESBYTITLE <--
console.log(taskSchedule) // THIS PRINTS UNDEFINED <------------
const addResponse = await SchedulesDAO.addTask(
taskTitle, taskRepeat, taskFrequency, taskStart, taskEnd, taskSchedule
)
res.json({status:"success"})
}catch(e){
res.status(500).json({error: e.message})
}
}
GetScheduleByTitle Function:
static async GetScheduleByTitle(title) {
let query = {title: title}
let idString = ""
let cursor
try{
cursor = await schedules.find(query)
}catch (e) {
console.error("Unable to issue find command: " + e)
return {schedule: []}
}
cursor.toArray(function(err, results){
console.log(results[0]._id.toString()) //THIS PRINTS THE RIGHT ID STRING <-------------
idString = results[0]._id.toString()
return idString
})
}
I haven't been able to figure out exactly what I am missing. Please let me know if it would be helpful to see any other code.
Most of your code is fine. The issue lies in the fact that you are using a callback within your GetScheduleByTitle function:
async function () {
cursor.toArray(function(err, results){
console.log(results[0]._id.toString()) //THIS PRINTS THE RIGHT ID STRING <-------------
idString = results[0]._id.toString()
return idString
})
// implicit return undefined
}
What is happening is that your cursor.toArray() is being called, as you expect, but it is then continuing execution onto the implicit undefined return. Your function returns undefined before any of the callback logic is even processed.
The way to fix this:
try {
const results = await cursor.toArray()
let idString = results[0]._id.toString()
return idString
} catch (err) {
console.trace(err)
throw new Error(err)
}
Use the asynchronous promise based method.
If one does not exist, you could create a wrapper for a callback only function like so:
const cursorToArray = async (cursor) => {
return new Promise((resolve, reject) => {
cursor.toArray(function(err, results){
if (results)
resolve(results)
else
reject(err)
})
})
}

How to call a custom function synchronously in node js?

I am developing a server project which needs to call some functions synchronously. Currently I am calling it in asynchronous nature. I found some similar questions on StackOverflow and I can't understand how to apply those solutions to my code. Yet I tried using async/await and ended up with an error The 'await' operator can only be used in an 'async' function
Here is my implementation
function findSuitableRoom(_lecturer, _sessionDay, _sessionTime, _sessionDuration, _sessionType){
let assignedRoom = selectRoomByLevel(preferredRooms, lecturer.level, _sessionDuration); <------- Need to be call synchronously
if (!assignedRoom.success){
let rooms = getRooms(_sessionType); <------- Need to be call synchronously
assignedRoom = assignRoom(_lecturer.rooms, _sessionDuration, _lecturer.level);
} else {
arr_RemovedSessions.push(assignedRoom.removed)
}
return assignedRoom;
}
function getRooms(type){
switch (type){
case 'Tutorial' : type = 'Lecture hall'
break;
case 'Practical' : type = 'Lab'
break;
default : type = 'Lecture hall'
}
Rooms.find({type : type},
(err, rooms) => {
if (!err){
console.log('retrieved rooms ' + rooms)
return rooms;
}
})
}
Here I have provided only two methods because full implementation is very long and I feel if I could understand how to apply synchronous way to one method, I can manage the rest of the methods. Can someone please help me?
Well yes await is only available inside an async function so put async infront of findSuitableRoom.
Also you did a classic mistake. You use return inside of a callback function, and expect getRooms to return you some value.
async function findSuitableRoom(
_lecturer,
_sessionDay,
_sessionTime,
_sessionDuration,
_sessionType
) {
let assignedRoom = selectRoomByLevel(
preferredRooms,
lecturer.level,
_sessionDuration
);
if (!assignedRoom.success) {
try {
let rooms = await getRooms(_sessionType);
} catch (err) {
console.log("no rooms found");
}
assignedRoom = assignRoom(
_lecturer.rooms,
_sessionDuration,
_lecturer.level
);
} else {
arr_RemovedSessions.push(assignedRoom.removed);
}
return assignedRoom;
}
Also wrap it in an try / catch
Since .find() returns an promise if you dont pass an callback you can write it like this
function getRooms(type) {
switch (type) {
case "Tutorial":
type = "Lecture hall";
break;
case "Practical":
type = "Lab";
break;
default:
type = "Lecture hall";
}
return Rooms.find({ type });
}
Note here findSuitableRoom is no longer synchronouse. Its async and returns an promise. That means you will need to use the function like this:
findSuitableRoom.then(res => { console.log(res); })
The 'await' operator can only be used in an 'async' function
This means whenever you want to use the await keyword it needs to be inside a function which has an async keyword (returns promise)
read this https://javascript.info/async-await for more info
const add = (a, b) => {
return new Promise((resolve, reject) => {
setTimeout(() => { //to make it asynchronous
if (a < 0 || b < 0) {
return reject("don't need negative");
}
resolve(a + b);
}, 2000);
});
};
const jatin = async () => {
try{
const sum = await add(10, 5);
const sum2 = await add(sum, -100);
const sum3 = await add(sum2, 1000);
return sum3;
} catch (e) {
console.log(e);
}
};
jatin()
Try this
let's understand this
add is a normal function that does some asynchronous action like
waiting for 2 seconds
normally we use await with async function so in order to use it we make as async function jatin and use await with add function call
to make it synchronous, so until first await add call() doesn't
happen it wont execute another await add call().
Example code if you will use in your app.js
router.post("/users/login", async (req, res) => {
try {
const user = await User.findByCredentials(
req.body.email,
req.body.password
);
const token = await user.generateToken();
res.status(200).send({
user,
token,
});
}
catch (error) {
console.log(error);
res.status(400).send();
}
});

await not working for insert command in nodejs

I have an array of addons and I want to insert them into the db table.
var addons = [sample,sample,.....]
return new Promise((resolve,reject) => {
addons.foEach(async addon => {
// first check if the items is in db
const response = await Kinex.where({}).from('table_name');
if(response.length == 0){
// insert new record
const insertResp = kinex('table_name').insert(addon)
addon.system_id = insertResp[0];
}else{
addon.system_id = response[0].id;
}
})
})
What I expected is to have unique record in the database, but the above code produced duplicate record in the database. Please help to find out the issue with the code.
The problem is running async function inside a loop. As mentioned by #Felix, forEach doesn't know about async functions and doesn't wait for your where query to return. If you wanna do things in async manner inside loops, you can do it with for..of loops. Also make sure to always use try/catch blocks while using async/await. Below is the code in your case:
const addons = [sample,sample,.....];
return new Promise(async (resolve, reject) => {
try {
for (let addon of addons) {
// first check if the items is in db
const response = await Kinex.where({}).from('table_name');
if (response.length) {
const insertResp = await kinex('table_name').insert(addon)
addon.system_id = insertResp[0];
} else addon.system_id = response[0].id;
resolve(); // resolve with whatever you wants to return
}
} catch (e) {
reject(e)
}
});
You can read more on for..of with async/await here.
As pointed by #Sándor, here's the code using Promise.all:
var addons = [sample, sample, .....]
return Promise.all(addons.map(async addon => {
// Do your async stuff here
// first check if the items is in db
const response = await Kinex.where({}).from('table_name');
if (response.length == 0) {
// insert new record
const insertResp = kinex('table_name').insert(addon)
addon.system_id = insertResp[0];
} else {
addon.system_id = response[0].id;
}
}))

How to push an object into an array in async function

i have been trying to insert an object into an array in async function ,but it
return an empty array as output in nodejs ,mongoose
var data = [];
app.get("/api/post", async (req, res) => {
const post = await UserPost.find();
post.forEach(async element => {
const email = await element.userid;
const user = await Account.find({ email });
const usern = await user[0].username;
var userobject = {
element,
usern
};
//Promise.all(userobject)
data.push(userobject);
});
console.log(data);
res.send({ data });
});
It seems you are struggling with promises. In order to achieve this specific scenario, you can use Promise.all and Array.map.
Here is a code I edited for you:
(*please note that this is just a dummy code for the sake of explanation)
app.get("/api/post", async (req, res) => {
try {
const posts = await dummyPromiseResolver(); // first promise
const promises = posts.map(async element => {
const user = await dummyEmailReturn(element.userid); // second promise
const usern = user[0].username;
return {
usern,
...element
};
});
const fresult = await Promise.all(promises);
res.send(fresult);
} catch (error) {
console.error("error in posts fetch:" + error);
}
});
If I describe this code, posts.map is creating an Array of promises since we need to iterate through every object in the array and needs to add values from separate promises.
Then Promise.all can execute your promise array and return final results array with your desired results.
Note: You can also use for … of as well but when we need to happen things parallelly we use Promise.all. You can find more information from this thread.
here is a link for code sandbox: https://codesandbox.io/embed/serverless-cookies-nu4h0
Please note that I have added dummyPromiseResolver and dummyEmailReturn which would be equal to UserPost.find() and Account.find() functions respectively. In addition to that, I removed a few unnecessary awaits in your code. I added a try catch block to catch any exceptions. You can change that try catch as you please.
hope this will help you. let me know if you need more clarifications.

NodeJS Async / Await - Build configuration file with API call

I would like to have a configuration file with variables set with data I fetch from an API.
I think I must use async and await features to do so, otherwise my variable would stay undefined.
But I don't know how to integrate this and keep the node exports.myVariable = myData available within an async function ?
Below is the code I tried to write to do so (all in the same file) :
const fetchAPI = function(jsonQuery) {
return new Promise(function (resolve, reject) {
var reqOptions = {
headers: apiHeaders,
json:jsonQuery,
}
request.post(apiURL, function (error, res, body) {
if (!error && res.statusCode == 200) {
resolve(body);
} else {
reject(error);
}
});
});
}
var wallsData = {}
const fetchWalls = async function (){
var jsonQuery = [{ "recordType": "page","query": "pageTemplate = 1011"}]
let body = await utils.fetchAPI(jsonQuery)
let pageList = await body[0].dataHashes
for(i=0;i<pageList.length;i++){
var page = pageList[i]
wallsData[page.title.fr] = [page.difficultyList,page.wallType]
}
return wallsData
throw new Error("WOOPS")
}
try{
const wallsData = fetchWalls()
console.log(wallsData)
exports.wallsData = wallsData
}catch(err){
console.log(err)
}
The output of console.log(wallsData) shows Promise { <pending> }, therefore it is not resolved and the configuration file keep being executed without the data in wallsData...
What do I miss ?
Thanks,
Cheers
A promise is a special object that either succeeds with a result or fails with a rejection. The async-await-syntax is syntactic sugar to help to deal with promises.
If you define a function as aync it always will return a promise.
Even a function like that reads like
const foo = async() => {
return "hello";
}
returns a promise of a string, not only a string. And you need to wait until it's been resolved or rejected.
It's analogue to:
const foo = async() => {
return Promise.resolve("Hello");
}
or:
const foo = async() => {
return new Promise(resolve => resolve("Hello"));
}
Your fetchWalls similarly is a promise that will remain pending for a time. You'll have to make sure it either succeeds or fails by setting up the then or catch handlers in your outer scope:
fetchWalls()
.then(console.log)
.catch(console.error);
The outer scope is never async, so you cannot use await there. You can only use await inside other async functions.
I would also not use your try-catch for that outer scope promise handling. I think you are confusing the try-catch approach that is intended to be used within async functions, as there it helps to avoid nesting and reads like synchronous code:
E.g. you could do inside your fetchWalls defintion:
const fetchWalls = async function (){
var jsonQuery = [{ "recordType": "page","query": "pageTemplate = 1011"}]
try {
let body = await utils.fetchAPI(jsonQuery)
} catch(e) {
// e is the reason of the promise rejection if you want to decide what to do based on it. If you would not catch it, the rejection would chain through to the first error handler.
}
...
}
Can you change the statements like,
try{
const wallsData = fetchWalls();
wallsData.then((result) => {
console.log(result);
});
exports.wallsData = wallsData; // when importing in other file this returns as promise and we should use async/await to handle this.
}catch(err){
console.log(err)
}

Resources