I am using node-async-loop for asyncronous programming
var array = ['item0', 'item1', 'item2'];
asyncLoop(array, function (item, next)
{
do.some.action(item, function (err)
{
if (err)
{
next(err);
return;
}
next();
});
}, function (err)
{
if (err)
{
console.error('Error: ' + err.message);
return;
}
console.log('Finished!');
});
Like this I am using three async loops one under one.
I want to send the response only after the third inner loop ends. How can I do so?.
Here is the link for node-async-loop (https://www.npmjs.com/package/node-async-loop)
here is my code which i writing but whnever i want to response when the last loop completes it say can set header after send to cliend.
also in console log i am getting data every time when data coming from query.
const id = req.params.id;
finalData = [];
tb_user.findOne({ where: { id: id } }).then((userRiverSys, err) => {
if (userRiverSys) {
// console.log(userRiverSys.regionJson)
asyncLoop(userRiverSys.regionJson, function (item, next) {
// console.log("item", item);
tb_riverSystems.findAll(
{
where: { regionId: item.id }
}).then((findriverSys, err) => {
if (err) {
next(err);
return;
}
// console.log("findriverSys", findriverSys);
if (findriverSys) {
asyncLoop(findriverSys, function (item1, next1) {
if (err) {
next(err);
return;
}
// console.log("item1", item1.dataValues);
tb_facilities.findAll(
{
where: { riverSystemId: item1.dataValues.id }
}).then((findFacilities) => {
if (findFacilities) {
// console.log("findFacilities", findFacilities[0].dataValues.name);
asyncLoop(findFacilities, function (item2, next2) {
if (err) {
next(err);
return;
}
tb_userAccess.findAll(
{
where: { facilityId: item2.dataValues.id }
}).then((userAccessFacilities, err) => {
// console.log("userAccessFacilities", userAccessFacilities[0].dataValues);
// var i = 0;
asyncLoop(userAccessFacilities, function (item3, next3) {
finalData.push({
UserId: item3.userid,
facilityId: item3.facilityId,
})
next3();
},
function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
// i++;
// console.log('Finished!!!!');
// if (userAccessFacilities.length === i) {
// console.log("finalData", i);
// // res.json({"status":"true", "message":"update OrgChallenge"})
// }
})
return res.json({"status":"true", "message":"update OrgChallenge"})
// console.log("finalData", finalData);
})
next2();
}, function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
console.log('Finished!!!');
});
}
});
next1();
}, function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
console.log('Finished!!');
});
}
});
next();
}, function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
console.log('Finished!');
});
} else {
console.log("err3", err)
}
})
If you promisify your asynchronous action (so it returns a promise), then you can just use a regular for loop and async/await and there is no need for a 3rd party library to sequence your asynchronous loop. This is modern Javascript:
const { promisify } = require('util');
do.some.actionP = promisify(do.some.action);
async function someFunction() {
const array = ['item0', 'item1', 'item2'];
for (let item of array) {
let result = await do.some.actionP(item);
// do something with result here
}
return someFinalResult;
}
someFunction().then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
FYI, in real code, many (or even most) asynchronous operations now offer promisified versions of their API already so usually you don't even need to do the promisify step any more. For example, pretty much all databases already offer a promise interface that you can just use directly.
const loop = async (arr, results = []) => {
const item = arr.shift()
if (!item) {
console.log("DONE");
return results;
}
// as async function
await new Promise(resolve => {
resolve(results.push(`asynced-${item}`))
})
return loop(arr, results);
}
(async () => {
const result = await loop(["item0", "item1", "item2"])
console.log(result);
})();
I'd be happy if I can help you.
but this script uses a recursive function instead of node-async-loop.
so this might not be suitable for you.
Related
I am using node js function i have written the code long before but i need to add async and await in my functions i don know how to proceed with my code structure .
Here is my code structure
app.express.get('/api/member/logout', function (request, response) {
functionBal.logout(request.query.abc).then(function (result) {
if (result) {
response.set('Content-Type', 'application/json');
response.status(200);
response.json(result);
}
}).catch(function (err) {
response.set('Content-Type', 'application/json');
response.status(400);
response.json("Error -- " + err);
});
});
module.exports.log = function (abc) {
return new app.promise(function (resolve, reject) {
functionDal.log(abc).then(function (result) {
if (result)
resolve(result);
else {
reject("Error");
}
}).catch(function (err) {
reject(err);
});
})
};
module.exports.log = function (abc) {
return new app.promise(function (resolve, reject) {
mySqlConnection.connection().then(function (con) {
con.query("UPDATE member SET table1 = 0 WHERE abc = ?", [abc]).then(function (rows, fields) {
resolve('success');
}).catch(function (err) {
reject(err);
});
}).catch(function (err) {
reject(err);
});
});
}
Please help in adding async await in this coding structure
Give this is try.
app.express.get('/api/member/logout', async function (request, response) {
try {
let data = await functionBal.logout(request.query.abc)
response.set('Content-Type', 'application/json');
response.status(200);
response.json(result);
} catch (error) {
response.set('Content-Type', 'application/json');
response.status(400);
response.json("Error -- " + err);
}
});
module.exports.log = async function (abc) {
try {
return await functionDal.log(abc)
} catch (error) {
throw error
}
};
module.exports.log = async function (abc) {
try {
const con = await mySqlConnection.connection()
await con.query("UPDATE member SET table1 = 0 WHERE abc = ?", [abc])
return 'success'
} catch (error) {
throw error
}
}
Make sure, you have Node.js 8+.
In my nodejs project, there's a function where I have two queries to get data from. First query is dependent on a flag, if flag is true, then I've to run that query and pass its data to second query. Otherwise I've to set some hard-coded data for second query. But it does not wait for first query response and run second query. I've added callbacks to it but nothing worked for me. Here is my code snippet;
getData(req, callback) {
if(!req.flag){
lstData.push('d');// hardcoded data
return Reader.open(filename).then(reader => {
let code = reader.data;
if(!!code ){
return dao.getFirstData(code , (err, results) => {
if (err) return callback(err);
if(results && results.length > 0){
return lstData = results;
}
});
}
});
}
else{
lstData.push('d');// hardcoded data
}
let asyncFuncs = [
(callback) => {
dao.getSecondData(lstData, (err, results) => {
if (err) return callback(err);
return callback(null, { amounts: results });
});
}
];
asyncFuncs.push(callback => {
dao.thirdFunction(id, callback);
});
async.parallel(asyncFuncs, (err, results) => {
if (err) return callback(err);
let data1= results[0].amount;
let data2= results[1];
// some calculations with data1 & data2
return callback(err, finalResult);
});
}
No matter flag is true or false, getSecondData always returns data against d (hard-coded value). I am a newbie to nodejs, so please let me know what am I doing wrong.
SO I updated my code to add promise in it...here is updated code;
getData(req, callback) {
if(!req.flag){
lstData.push('d');// hardcoded data
Reader.open(filename).then(reader => {
let code = reader.data;
if(!!code ){
var prom = new Promise((resolve, reject) => {
dao.getFirstData(code , (err, results) => {
if (err) return callback(err);
if(results && results.length > 0){
let lstData = results;
return resolve(lstData);
}
});
});
prom.then((result) => {
return result;
});
}
});
}
else{
lstData.push('d');// hardcoded data
}
let asyncFuncs = [
(callback) => {
dao.getSecondData(lstData, (err, results) => {
if (err) return callback(err);
return callback(null, { amounts: results });
});
}
];
asyncFuncs.push(callback => {
dao.thirdFunction(id, callback);
});
async.parallel(asyncFuncs, (err, results) => {
if (err) return callback(err);
let data1= results[0].amount;
let data2= results[1];
// some calculations with data1 & data2
return callback(err, finalResult);
});
}
But still same response. It is not waiting for promise result.
There plenty of ways to achieve this but I would prefer http://async.io/ to perform multi function operations.
By using promise you can do,
function f1(argument){
return new Promise((resolve, reject) => {
try {
data = // do your thing
resolve(data)
}
catch(err){
reject(err)
}
})
}
and then use await to achieve this
async function caller(){
await f1()
}
Few other links to help you [here][2]
[2]: https://stackoverflow.com/questions/22442321/callback-function-example/48333938#:~:text=A%20callback%20function%2C%20is%20a,or%20executed)%20inside%20the%20otherFunction.&text=Without%20thinking%20too%20much%2C%20see%20the%20following%20example.&text=Generally%2C%20JavaScript%20allows%20function%20as%20a%20parameter.
You can use async/await for asynchronous calls or you can uses promises. This will wait at the asynchronous calls and once you get the response your code will execute the dependent subsequent calls.
getData(req, callback) {
if(!req.flag){
lstData.push('d');// hardcoded data --> this might be an issue as you are already pushing data.
// these are async calls where you can ask your code to wait
return Reader.open(filename).then(reader => {
let code = reader.data;
if(!!code ){
var promise = dao.getFirstData(code , (err, results) => {
if (err) reject(err);
if(results && results.length > 0){
lstData = results;
resolve(lstData);
}
});
return promise --> you can subscribe this using then
}
});
}
else{
lstData.push('d');// hardcoded data
}
let asyncFuncs = [
(callback) => {
dao.getSecondData(lstData, (err, results) => {
if (err) return callback(err);
return callback(null, { amounts: results });
});
}
];
}
To get hands on this you can check the ways of using async/await
https://javascript.info/async-await
I am trying to call method get_radar_life_cycle from app.get("/api/radar_cloning and it throws the error shown below,
error is coming from line return done(null,documents) how do I return documents back to my API call?
METHODS:-
let get_cloned_radars = function(documents, done) {
let complete_radar_list=[]
for (let i = 0; i < documents.length; i++) {
complete_radar_list.push(documents[i]['orgRadar']);
for (let j = 0; j < documents[i]['clonedRadarsdetailslist'].length; j++) {
complete_radar_list.push(documents[i]['clonedRadarsdetailslist'][j]['clonedRadar']);
}
}
data = complete_radar_list
return done(null, data)
}
let get_radar_life_cycle = function(data,done) {
console.log("data after get_radar_life_cycle")
console.log(data)
Radar_life_cycle.find({orgRadar: {$in:data}})
.then(documents => {
console.log(documents) --> shows correct data
});
return done(null,documents) --> Error is coming from this line
};
API call:
app.get("/api/radar_cloning", (req, res, next) => {
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => {
get_cloned_radars(documents, function(err,data) {
if (err) {
res.json(err);
if (data!=null){
console.log(data)
}//end for data
}//end of (Err)
});//get_cloned_radars
get_radar_life_cycle(data, function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
}//end for radar_life_cycle_data
}//end of (Err)
});//end of get_radar_life_cycle
});
});
ERROR:-
(node:10065) UnhandledPromiseRejectionWarning: ReferenceError: documents is not defined
You are trying to access documents outside of its scope, the scope being everything between the { and }. So you cannot access it below the .then(() => {}) scope.
Luckily you are are providing a callback function called done(err, radar_life_cycle_data), which you can use anywhere in the scope of the get_radar_life_cycle(documents, done) function. Even the scopes inside of its scope. When you are calling the done function, what you are basically doing is calling this function (well it has some syntax errors, so I cleaned it up)
function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
}
}//end for radar_life_cycle_data
which then gets executed
So the solution:
Move your done in your .then(() => {}) scope like this:
let get_radar_life_cycle = function(data,done) {
console.log("data after get_radar_life_cycle")
console.log(data)
Radar_life_cycle.find({orgRadar: {$in:data}})
.then(documents => {
console.log(documents) // --> shows correct data
done(null,documents) // --> No error coming from this line
});
};
Same goes for the data it is not in the scope of the get_cloned_radars
app.get("/api/radar_cloning", (req, res, next) => {
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => {
get_cloned_radars(documents, function(err,data) {
if (err) {
res.json(err);
if (data!=null) {
console.log(data)
get_radar_life_cycle(data, function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
} //end of (Err)
}); //end of get_radar_life_cycle
} //end for data
} //end of (Err)
}); //get_cloned_radars
});
But since your code is unreadable, here is a cleaned up version:
app.get("/api/radar_cloning", (req, res, next) => {
const radar_life_cycle_cb = function (err, data) {
if (err) {
res.json(err);
return;
}
console.log(data);
}
const cloned_radar_cb = function (err, data) {
if (err) {
res.json(err);
return;
}
if (data != null) {
get_radar_life_cycle(data, radar_life_cycle_cb);
}
};
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => get_cloned_radars(documents, cloned_radar_cb));
}
Hi I have a problem running a loop and getting the return data using Promises.
I have a getStudentMarks method for getting students marks from the database in subject wise.
getStudentMarks: function(studentId, studentStandard) {
console.log("getStudentMarks invoked...");
return new Promise(function(resolve, reject) {
r.table('student_subjects').filter({
"studentId": studentId,
"studentStandard": studentStandard
}).pluck("subjectId", "subjectName").run(connection, function(err, cursor) {
if (err) {
throw err;
reject(err);
} else {
cursor.toArray(function(err, result) {
if (err) {
throw err
} else {
console.log(result.length);
if (result.length > 0) {
studentSubjectArray = result;
var studentMarksSubjectWiseArray = [];
studentSubjectArray.forEach(function(elementPhoto) {
r.table('student_marks').filter({
"studentId": studentId,
"subjectId": studentSubjectArray.subjectId
}).run(connection, function(err, cursor) {
if (err) {
throw err;
reject(err);
} else {
cursor.toArray(function(err, result_marks) {
var studnetMarksDataObject = {
subjectId: studentSubjectArray.subjectId,
subjectName: studentSubjectArray.subjectName,
marks: result.marks
};
studentMarksSubjectWiseArray.push(studnetMarksDataObject);
});
}
});
});
resolve(studentMarksSubjectWiseArray);
}
}
});
}
});
});
}
I'm invoking the method by,
app.post('/getStudentMarks', function(req, reqs) {
ubm.getStudentMarks(req.body.studentId, req.body.studentStandard)
.then((data) => {
console.log('return data: ' + data);
})
.catch((err) => {
console.log(err);
});
});
When I run the code its working absolutely fine there is no error. I get all the student marks object in the studentMarksSubjectWiseArray array. But the problem is even before the studentSubjectArray loops gets completed, the resolve is getting executed and I'm getting a blank array as return. How do I solve the problem. I understand that I'm not doing the Promises right. I'm new to Promises so I'm not being able to figure out the right way.
That happens because inside your studentSubjectArray.forEach statement you perform set of asynchronous operations r.table(...).filter(...).run() and you push their result into the array. However, those actions finish after you perform the resolve(), so the studentMarksSubjectWiseArray is still empty. In this case you would have to use Promise.all() method.
let promisesArray = [];
studentSubjectArray.forEach((elementPhoto) => {
let singlePromise = new Promise((resolve, reject) => {
// here perform asynchronous operation and do the resolve with single result like r.table(...).filter(...).run()
// in the end you would perform resolve(studentMarksDataObject)
r.table('student_marks').filter({
"studentId": studentId,
"subjectId": studentSubjectArray.subjectId
}).run(connection, function(err, cursor) {
if (err) {
throw err;
reject(err);
} else {
cursor.toArray(function(err, result_marks) {
var studnetMarksDataObject = {
subjectId: studentSubjectArray.subjectId,
subjectName: studentSubjectArray.subjectName,
marks: result.marks
};
resolve(studnetMarksDataObject);
});
}
});
});
promisesArray.push(singlePromise)
});
Promise.all(promisesArray).then((result) => {
// here the result would be an array of results from previously performed set of asynchronous operations
});
var shortLinks = [];
Link.find({}, function (err, links) {
if (err) {
console.log(err);
} else {
links.map(link => {
shortLinks.push(link.shortLink);
});
}
console.log(shortLinks);//shortLinks has values, all okey
});
console.log(shortLinks); //shortLinks is empty
i need to use shortLinks after Link.find({}) but array is empty.
Need to return shortLinks.
Callbacks. The function(err, links) is called asynchronously, so shortLinks isn't populated until that function is called. Your bottom console.log is being called first, due to how callbacks work.
https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes/Declaring_and_Using_Callbacks
need to use promise:
const shortLinks = [];
const getShortLinks = Link.find({}, function (err, links) {
if (err) {
console.log(err);
} else {
links.map(link => {
shortLinks.push(link.shortLink);
});
}
});
getShortLinks.then(function(links){
console.log(shortLinks);
}, function(err){
console.log(err);
});