await statement does not "wait" - node.js

So I've got a function which is :
module.exports.play = async (client, channel, players) => {
players.push(client.guilds.cache.first().members.cache.array().filter(mem => mem.user.username === "user1").map(mem => mem.user)[0]);
players.push(client.guilds.cache.first().members.cache.array().filter(mem => mem.user.username === "users2").map(mem => mem.user)[0]);
try {
await beginMessage(players, channel);
let playersCards = await beginGame(client, players);
console.log(playersCards);
emitter.on("stop", async () => {
await channel.delete();
console.log("jeu fini");
});
}
catch(e) {
console.error(e);
}
};
and the is that the value of my variable 'playersCards' is print before the value is returned by the async function "beginGame". Here's beginGame's function code :
async function beginGame(client, players) {
let playersCards = [];
fs.readFile("Utils/cartes.json", 'utf8', async (err, data) => {
if(err) console.log(err);
let cartes = JSON.parse(data);
cartes = cartes.cartes;
await asyncForEach(players, async player => {
let playerCards = await distributeCards(player, cartes);
playersCards.push(playerCards);
});
return playersCards;
});
}
Where could the problem be ?

Because beginGame returns a Promise with no value because fs.readFile took a callback which is called else where, so there is nothing to wait for.
async function beginGame(client, players) {
return new Promise(async (resolve, reject) => {
let playersCards = [];
return fs.readFile('Utils/cartes.json', 'utf8', async (err, data) => {
if (err) return reject(err);
let cartes = JSON.parse(data);
cartes = cartes.cartes;
await asyncForEach(players, async player => {
let playerCards = await distributeCards(player, cartes);
playersCards.push(playerCards);
});
return resolve(playersCards);
});
});
}
this should work since the function is wrapped with promise and there is something to wait for.

Related

Await Promise.all async does't work in my code

I have a lambda function with the structure below,
It used to work in older versions of nodejs but it doesn't work with the newer versions.
I know my code structure is quite messy and wrong but I can't get my head around it. I'm trying to use Promise.all but I'm obviously doing something wrong cause it's not getting executed at all.
By the way, I'm not getting any errors. The promise.all method never gets executed.
let AWS = require('aws-sdk');
exports.handler = async(event, context, callback) => {
let result = {};
try {
result = await getOrder(sql, 0);
result.map(
(dataField) => {
});
}
catch (error) {
console.log(error);
callback(error);
}
var today_result = [];
const groupKey = i => i.user_id + '_' + i.when;
const counts = _.countBy(followingsIDs, groupKey);
const isMulti = i => counts[groupKey(i)] > 1;
const multiPropkey = i => ({ multiplekey: isMulti(i) ? groupKey(i) : groupKey(i) });
const multiProp = i => ({ multiple: isMulti(i) ? counts[groupKey(i)] : 1 });
const updated = _.map(followingsIDs, i => _.extend(i, multiProp(i), multiPropkey(i)));
const uniqResult = _.uniq(updated, function(d) { return d.multiplekey });
// Doesn’t execute from here —>
await Promise.all(uniqResult.map(async(dataField) => {
console.log("test_");
dosomething()
if (true) {
let sql = `INSERT INTO ….`
result = await getOrder(sql, 0);
try {
const data = await sns.publish(params).promise();
}
catch (e) {
console.log(e.stack);
response.result = 'Error';
}
}
}));
// Till here <----
callback(null, uniqResult);
};
let getOrder = async(sql, params) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) throw err;
connection.query(sql, params, (err, results) => {
if (err) {
reject(err);
}
// console.log("-----Query Done!");
connection.release();
// console.log("-----Data: ", results);
resolve(results);
});
});
});
};
What are you awaiting to? The uniqResult is just declared as an empty array. Immediately after that you pass it to Promise.all. You need to fill it with Promises and then pass it to Promise.all.

Node Lambda returns null for AWS console

The following code works great locally, but after deploying it to AWS Lambda and running it my records are not saving to DynamoDB and I'm getting a return of null from Lambda.
I know it's not a permissions issue with the Lambda execution role because I can successfully insert one individual record into DynamoDB from the AWS console.
I think the issue has to do with the .forEach loop and how the aws-sdk works. I'm not sure I'm completely wrapping my head around how to properly use JavaScript promises with Lambda. Any help is greatly appreciated!
module.exports.handler = async event => {
const getItems = () => {... // return items //...}
const addToDb = (items) => {
items.forEach(item => {
var params = {
Item: {"id": {S: item.id}, "title": {S: item.title}},
ReturnConsumedCapacity: "TOTAL",
TableName: "my-table"
};
dynamodb.putItem(params, (err, data) => {
if (err) console.log(err, err.stack);
else console.log(data);
});
});
};
const getItemsPromise = new Promise((resolve) => {
const items = getItems();
const itemsAddedToDb = addToDb(items);
resolve(itemsAddedToDb);
});
return getItemsPromise
.catch(err => console.log(err));
};
This should work!
exports.handler = (event) => {
const getItems = () => {...} // assuming getItems returns promise
const addToDb = (items) => {
asyncForEach(items, async (item) => {
const params = {
Item: {
id: {
S: item.id
},
title: {
S: item.title
}
},
ReturnConsumedCapacity: 'TOTAL',
TableName: 'my-table'
}
await dynamodb.putItem(params, (err, data) => {
if (err) console.log(err, err.stack)
else console.log(data)
})
})
}
const getItemsPromise = new Promise(async (resolve) => { // rule eslintno-async-promise-executor - use then instead
const items = await getItems()
const itemsAddedToDb = await addToDb(items)
resolve(itemsAddedToDb)
})
const asyncForEach = async (array, callback) => {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array)
}
}
return getItemsPromise.catch((err) => console.log(err))
}
Notice:
async for export.handler has no use. use async only if function has await inside it.
async await doesn't support for forEach try for loop instead

promise all not working as expected while working with list

I want the callback to return the response when promise all finishes. I am getting the response before promise all. Batch List is empty in response, as it is returned before promise all.
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback){
var results = {};
var requestList = [];
var batchList = [];
var response = {};
new Promise((resolve, reject) => {
this.getRequestList(object, limit, lastEvaluatedKey,function (err, result) {
console.log(result);
results = result;
if(err) {
reject();
} else {
resolve();
}
});
}).then(async () =>
{
requestList = requestList.concat(results.items);
const runAsyncFunctions = async () => {
var promises = [];
requestList.map(async request => {
var promise = await this.getBatchList(request.requestID.S, mode, null, null, function(err, result) {
batchList = batchList.concat(result.items);
});
promises.concat(promise);
});
await Promise.all(
promises
).then(()=>{
response = {
"requests": requestList,
"batches": batchList,
"lastEvaluatedKey": results.LastEvaluatedKey
};
callback("", response);
}).catch((error) => {
console.log(error);
});
};
await runAsyncFunctions();
}).catch((error) => {
callback(error, response);
});
}
promises is not an array of promises.
The line
var promise = await this.getBatchList(request.requestID.S, mode, null, null, function(err, result) {
batchList = batchList.concat(result.items);
});
is executed later then
callback("", response)
I guess you want to do something like this
var promises = [];
for (const request of requestList) {
const promise = this.getBatchList(request.requestID.S, mode, null, null, function (err, result) {
batchList = batchList.concat(result.items);
});
promises.push(promise);
}
await Promise.all(
...
The correct way of doing it is:
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback){
var results = {};
var requestList = [];
var batchList = [];
var response = {};
new Promise((resolve, reject) => {
this.getRequestList(object, limit, lastEvaluatedKey,function (err, result) {
console.log(result);
results = result;
if(err){
reject(err);
}
else{
resolve();
}
});
return results;
}).then(() =>
{
requestList = requestList.concat(results.items);
var iteration =0;
new Promise((resolve, reject) => {
for (let request of requestList) {
console.log(request.requestID.S);
this.getBatchList(request.requestID.S, mode, null, null, function (err, result) {
iteration++;
batchList = batchList.concat(result.items);
if(iteration === requestList.length)
{
resolve();
}
if(err)
{
reject();
}
});
}
}).then(()=>{
response = {
"requests": requestList,
"batches": batchList,
"lastEvaluatedKey": results.LastEvaluatedKey,
};
callback("", response);
}).catch((error) => {
callback(error, response);
});
}).catch((error) => {
callback(error, response);
});
}

Coinbase API large responses and slow

The following code takes a good 5 to 10 seconds to resolve (there are 5 API-calls). It's not usable as it is. Is the slow response my fault or is the Coinbase API just slow and large?
app.get('/buys', async (req, res) => {
const buys = await getAllBuys()
res.json(buys)
})
const fetchAllAccounts = () => {
return new Promise(
(resolve, reject) => {
coinbase.getAccounts(null, (err, accounts) => {
if (err) {
reject(err)
}
else{
resolve(accounts)
}
})
}
)
}
const fetchAllBuys = (account) => {
return new Promise(
(resolve, reject) => {
account.getBuys(null, (err, buys) => {
if (err) {
reject(err)
}
else{
resolve(buys)
}
})
}
)
}
const getAllBuys = async () => {
const accounts = await fetchAllAccounts()
let combinedBuys = []
for (let account of accounts) {
const buys = await fetchAllBuys(account)
combinedBuys = [...combinedBuys, ...buys]
}
//console.log(combinedBuys)
return combinedBuys
}
Response is a array with items that include account information like certificates and so on.
Ok, so it was my code. I the code above I wait for each request to finish before firing off a new one. Which results in unnecessary delay. With the Promise.all method we can generate all the promises and resolve them at the same time. Look at the refactored code bellow.
app.get('/buys', async (req, res) => {
console.time('[/buys]');
const promises = await getAllBuys()
const buys = await Promise.all(promises)
res.json(buys)
console.timeEnd('[/buys]');
})
const fetchAllAccounts = () => {
return new Promise(
(resolve, reject) => {
coinbase.getAccounts(null, (err, accounts) => {
if (err) {
reject(err)
}
else{
resolve(accounts)
}
})
}
)
}
const fetchAllBuys = (account) => {
return new Promise(
(resolve, reject) => {
account.getBuys(null, (err, buys) => {
if (err) {
reject(err)
}
else{
resolve(buys)
}
})
}
)
}
const getAllBuys = async () => {
const accounts = await fetchAllAccounts()
let promises = []
for (let account of accounts) {
promises.push(fetchAllBuys(account))
}
return promises
}
From 2,5 / 3 seconds to 0,8 / 1 second.

Async Await Node js

I am learning async await using node js
var testasync = async () =>
{
const result1 = await returnone();
return result1;
}
testasync().then((name)=>{
console.log(name);
}).catch((e) =>{
console.log(e);
});
var returnone = () =>{
return new Promise((resolve,reject)=>
{
setTimeout(()=>{
resolve('1');
},2000)
})
}
It fails with returnone is not a function. What am i doing wrong? calling the function just by itself work
returnone().then((name1) => {
console.log(name1)
})
Just calling the above code works
The reason you are getting this error because of hoisting. Your code seen by JS would look like this
var returnone;
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
returnone = () => {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
So the value of returnone is undefined.
You are assigning the function to the variable returnone at the end of the code, but you are trying to call that function before this assignment. You have two options to fix the code:
Option 1
Use a function declaration; this way, the function is hoisted and you can use it right from the start:
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
function returnone() {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
Option 2
Assign the function to the variable before you try to call it:
var returnone = () => {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});

Resources