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.
Related
I know for sure that my pullData module is getting the data back from the file read but the function calling it, though it has an await, is not getting the data.
This is the module (./initialise.js) that reads the data:
const fs = require('fs');
const getData = () => {
return new Promise((resolve, reject) => {
fs.readFile('./Sybernika.txt',
{ encoding: 'utf8', flag: 'r' },
function (err, data) {
if (err)
reject(err);
else
resolve(data);
});
});
};
module.exports = {getData};
And this is where it gets called (app.js):
const init = require('./initialise');
const pullData = async () => {
init.getData().then((data) => {
return data;
}).catch((err) => {
console.log(err);
});
};
const start = async() => {
let data = await pullData();
console.log(data);
}
start();
putting 'console.log(data)' just before return(data) in the resolve part of the call shows the data so I know it's being read OK. However, that final console.log shows my data variabkle as being undefined.
Any suggestions?
It's either
const pullData = async () => {
return init.getData().then((data) => {
return data;
}).catch((err) => {
console.log(err);
});
};
or
const pullData = async () =>
init.getData().then((data) => {
return data;
}).catch((err) => {
console.log(err);
});
Both versions make sure a promise returned by then/catch is passed down to the caller.
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
I'm trying to generate a screenshot from HTML
async function makeWeeklyReport(meterId, week) {
// get meters from meter
const meter = meters.find(it => it.prm === meterId);
const weeklyData = await generateWeeklyGraph(meter, week);
ejs.renderFile(path.join(__dirname, './views/partials/', "weekly_graph.ejs"), {
}, (err, data) => {
if (err) {
console.log(err)
return
}
console.log(data); // Actually printing good value
return data
});
}
When I invoke this function:
data = await makeWeeklyReport(meterId, week)
console.log("generated WeeklyReport", data) // returns undefined
data is undefined
but when I do console.log(data); in makeWeeklyReport(), it actually prints the html.
I thought the await keyword was supposed to wait the end of async function.
I already tried to put:
res.render(view, {.., async:true, ... }...)
but it is not working
How should I fix it ?
ejs.renderFile is not an async function/does not return a promise and will call the passed callback-function once it has finished rendering. Since you cannot directly return a value from a callback, rhis won't work.
However, you can wrap the call in a promise and resolve it, once the callback is called (note that I'm rejecting the promise in case of an error, you can change this of course and resolve the promise in that case as well instead):
async function makeWeeklyReport(meterId, week) {
const meter = meters.find(it => it.prm === meterId);
const weeklyData = await generateWeeklyGraph(meter, week);
return new Promise((resolve, reject) => {
// get meters from meter
ejs.renderFile(path.join(__dirname, './views/partials/', "weekly_graph.ejs"), {}, (err, data) => {
if (err) {
console.log(err)
return reject(err);
}
console.log(data); // Actually printing good value
resolve(data);
});
});
}
You can then await this function and process the resolved value:
data = await makeWeeklyReport(meterId, week);
This has nothing to do with async / await.
Your return statements are within a callback function, so nothing is returning in your makeWeeklyReport function.
You can use a Promise to unwrap the callback values.
async function makeWeeklyReport(meterId, week) {
// get meters from meter
const meter = meters.find(it => it.prm === meterId);
const weeklyData = await generateWeeklyGraph(meter, week);
const [err, data] = await new Promise(resolve => {
const p = path.join(__dirname, './views/partials/', "weekly_graph.ejs");
ejs.renderFile(p, { }, (err, data) => resolve([err, data]);
});
if (err) {
console.log(err);
return;
}
console.log(data); // Actually printing good value
return data;
}
To improve readability, you could even wrap renderFile as an async function:
function renderFileAsync(path, data) {
return new Promise(resolve => ejs.renderFile(path, data,
(err, data) => resolve([err, data]));
}
Then your makeWeeklyReport function could be written like this:
async function makeWeeklyReport(meterId, week) {
// get meters from meter
const meter = meters.find(it => it.prm === meterId);
const weeklyData = await generateWeeklyGraph(meter, week);
const p = path.join(__dirname, './views/partials/', "weekly_graph.ejs");
const [err, data] = await renderFileAsync(p, { });
if (err) {
throw err;
}
return data;
}
I am trying to return an array through async/await:
app.get('/users/article/feed',checkAuthenticated,async (request,response)=>{
try{
function executor(){
let articleArray=[]
const sql="SELECT noOfArticles FROM Articles WHERE id=?"
db.query(sql,[request.user.id], (err,result)=>{
if(err) throw err
let noOfArticles=result[0].noOfArticles
for(let i=1;i<=noOfArticles;i++){
const sql1="SELECT ?? FROM Articles WHERE id=?"
let index='article'+i
db.query(sql1,[index,request.user.id],(err,result)=>{
if(err) throw err
articleArray.push(result[0][index])
if(articleArray.length===noOfArticles){
console.log(articleArray); //here the array is printed as expected
return articleArray;
}
})
}
})
}
const resultArray= await executor();
console.log(resultArray); //here the array is undefined
response.render('viewArticles');
} catch(e){
console.log(e);
}
})
The resultArray is always undefined.
I know this is a very old question. I tried checking all the other answers in Stack Overflow but I am confused a lot about this. I am a newbie to js so I couldn't understand it properly. How can I solve this?
You are returning from inside the callback function, which won't work since executor doesn't wait for your queries responses. Return a Promise instead.
function executor() {
return new Promise((resolve,reject) => {
let articleArray = [];
const sql = "SELECT noOfArticles FROM Articles WHERE id=?";
db.query(sql, [request.user.id], (err, result) => {
if (err) return reject(err);
let noOfArticles = result[0].noOfArticles;
for (let i = 1; i <= noOfArticles; i++) {
const sql1 = "SELECT ?? FROM Articles WHERE id=?";
let index = "article" + i;
db.query(sql1, [index, request.user.id], (err, result) => {
if (err) return reject(err);
articleArray.push(result[0][index]);
if (articleArray.length === noOfArticles) {
console.log(articleArray); //here the array is printed as expected
return resolve(articleArray);
}
});
}
});
})
}
Does it return some result if you make the function you are calling async?
async function executor(){
let articleArray=[]
const sql="SELECT noOfArticles FROM Articles WHERE id=?"
db.query(sql,[request.user.id], (err,result)=>{
if(err) throw err
let noOfArticles=result[0].noOfArticles
for(let i=1;i<=noOfArticles;i++){
const sql1="SELECT ?? FROM Articles WHERE id=?"
let index='article'+i
db.query(sql1,[index,request.user.id],(err,result)=>{
if(err) throw err
articleArray.push(result[0][index])
if(articleArray.length===noOfArticles){
console.log(articleArray); //here the array is printed as expected
return articleArray;
}
})
}
})
}
When you return articleArray, you are not returning it from the executor function. Instead you are returning it from the callback that is passed into the db.query function. The () => {} syntax is basically shorthand for function() {} (although there are differences that are outside the scope of this answer).
Perhaps something like this might be helpful (note that I removed the try catch, as I believe such logging should be done at the middleware level in express, which it seems you are using):
app.get('/users/article/feed', checkAuthenticated, async (request, response) => {
return new Promise((resolve, reject) => {
let articleArray = []
const sql = "SELECT noOfArticles FROM Articles WHERE id=?"
db.query(sql, [request.user.id], (err, result) => {
if (err) reject(err)
let noOfArticles = result[0].noOfArticles
for (let i = 1; i <= noOfArticles; i++) {
const sql1 = "SELECT ?? FROM Articles WHERE id=?"
let index = 'article' + i
db.query(sql1, [index, request.user.id], (err, result) => {
if (err) reject(err); // reject the promise if there is an error
articleArray.push(result[0][index])
if (articleArray.length === noOfArticles) {
console.log(articleArray);
resolve(articleArray); // resolve the promise with the value we want
}
})
}
})
})
})
I m totally a newbie in nodejs.Trying to read a json file in a service and then use it in an other service.
It tells me that my service is undefined. What am i doing wrong ?
thanks in advance !
JsonService
'use strict';
const fs = require('fs');
exports.getJobs = ()=> {
fs.readFile('./common/data/jobs.json', (err, data) => {
if (err) throw err;
if (data) {
return new Promise(function (resolve, reject) {
resolve(data);
});
}
});
}
And JobsService
const JsonService = require('../../common/services/json.service');
exports.list = () => {
let jobs;
JsonService.getJobs().then((data)=>{
jobs = data;
return new Promise((resolve, reject) => {
if(jobs){
resolve(jobs);
}else{
reject(jobs)
}
});
});
};
If you just need to read the json file, you could simply do
const jobs = require("./common/data/jobs.json");
Hope this helps.
The reason why your code is not working because you are trying to use it as a promise but getJobs doesn't return a promise. You need to wrap it in promise and then return. This is the way
const fs = require("fs");
exports.getJobs = () => {
return new Promise((resolve, reject) => {
fs.readFile("./common/data/jobs.json", (err, data) => {
if (err) {
reject(err);
}
if (data) {
resolve(data);
}
});
});
};
and use it like this
const JsonService = require("../../common/services/json.service");
exports.list = () => {
let jobs;
JsonService.getJobs().then(data => {
console.log(data);
});
};
No need it wrap it in promise here.
But in your case simply requiring should work as I mentioned in above.