I have a function named looper2(), which is accepting an array of data, and im trying to get the id of each data from mysql database.All is working fine, but my nodejs is not waiting for the function, when its still represent await.
var noloop = [];
noloop = await looper2(json_array1);
console.log("db id returns",noloop)
console.log("no loop",noloop[0]); //im getting this undefined
function looper2(){
return new Promise(function(resolve, reject) {
// Do async job
for(var i=0;i<json_array1.length;i++){
var sl = "select id from json where name ="+db.escape(json_array1[i]);
db.query(sl, function(err,result) {
if (err) throw err;
console.log("individual id:", result)
noloop.push(result)
});
}
resolve(noloop)
});
}
The problem is that in looper2 function you resolve immediately after the forLoop and don't wait for the db queries to complete. You should instead resolve after the db queries have all completed
function looper2(){
return new Promise(function(resolve, reject) {
// Do async job
for(var i=0;i<json_array1.length;i++){
var sl = "select id from json where name ="+db.escape(json_array1[i]);
db.query(sl, function(err,result) {
if (err) throw err;
console.log("individual id:", result)
noloop.push(result)
if(noloop.length == json_array1.length) {
resolve(noloop)
}
});
}
});
}
You can't use await without async function. So, you have to create a self-executable function to use await like below. And if you are using promise inside a loop there is promise.all function available, you can use to resolve all pending promises.
(async () => {
var noloop = [];
noloop = await looper2(json_array1);
console.log(noloop);
})();
function async looper2(){
const promises = [];
for(var i=0;i<json_array1.length;i++){
var sl = "select id from json where name ="+db.escape(json_array1[i]);
db.query(sl, function(err,result) {
if (err) throw err;
promises.push(new Promise(result));
});
}
return Promise.all(promises)
}
Related
js
I just create a 2 function to send the response var = y but unfortunately res.end() work before then my y++ works..
This code work well with for loop without mine query
but when i used a query it working stop and it gives res like below.
Before promise call.
Loop completed.
Promise resolved: 0
Next step.
13289,
2170,
2165,
2146,
2115,
2138,
2143,
2112,
1964,
2685,
6945,
2687,
2688,
2902,
2935,
2941,
3094,
3095,
3164,
3096,
var http = require('http');
var url = require('url');
var fs = require('fs');
var mysql = require('mysql');
http.createServer(function (req, res) {
var q = url.parse(req.url, true);
var end = '';
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "justcode"
});
//1. Create a new function that returns a promise
function firstFunction() {
return new Promise((resolve, reject) => {
let arr = [];
con.connect(function (err) {
if (err) throw err;
con.query("SELECT * FROM wp_posts WHERE `post_type` = 'post'", async function (err, result, fields) {
if (err) throw err;
result.forEach(element => {
arr.push(element['ID']);
});
resolve(arr)
});
});
})
}
//2. Create an async function
async function secondFunction() {
//3. Await for the first function to complete
const result = await firstFunction()
res.end(JSON.stringify(result));
};
secondFunction()
}).listen(8080);
This is the working code::::
How about this...
//1. Create a new function that returns a promise
function firstFunction() {
return new Promise((resolve, reject) => {
let y = 0
con.connect(function (err) {
if (err) throw err;
con.query("SELECT * FROM wp_posts WHERE `post_type` = 'post'", async function (err, result, fields) {
if (err) throw err;
result.forEach(element => {
console.log(element['ID']);
y++;
});
// get the results from post table
console.log('Loop completed.')
resolve(y); // <---- Resolve the promise here
});
});
// for (i = 0; i < 100; i++) {
// y++
// }
// console.log('Loop completed.')
// resolve(y) // <--- Moving this inside con.query callback
})
}
//2. Create an async function,
async function secondFunction() {
console.log('Before promise call.')
//3. Await for the first function to complete
const result = await firstFunction()
console.log('Promise resolved: ' + result)
console.log('Next step.')
res.end();
};
secondFunction()
Problem in The Original Question
con.query is an asynchronous execution. It accepts a callback function which then it invokes once the operation has completed. javascript has something called runToCompletion in which the execution of a function continues until the last statement.
When secondFunction is invoked, it further invokes(with an await) firstFunction which returns a Promise and the execution of the promise starts, but the caller secondFunction is waiting for the promise to finish.
Inside the execution of the Promise of firstFunction, there is a call to con.query, which is an asynchronous call, but isn't being waited for. Hence, after invoking the call to con.query, the javascript execution continues further... only to encounter a resolve after a couple of statements. A resolve finishes the execution of the Promise of firstFunction and control passes back to secondFunction and then execution continues from there on. Now, since the call to con.query will finish after sometime, and when it does, the callback function will be executed. And so we are seeing the behavior as problematic. But it's all happening as per the semantics of javascript execution.
Assume you are using mysql, since it does not provide a promise API out of the box, you may need to promisify the connect() call and query() call yourself and await for them.
async function firstFunction() {
let y = 0;
await new Promise((resolve,reject)=>{
con.connect(function (err) {
if (err) reject(err);
resolve();
});
});
let result = await new Promise((resolve,reject)=>{
con.query("SELECT * FROM wp_posts WHERE `post_type` = 'post'", (err, result, fields) => {
if (err) reject(err);
resolve(result);
// get the results from post table
});
});
result.forEach(element => {
console.log(element['ID']);
y++;
});
// for (i = 0; i < 100; i++) {
// y++
// }
console.log('Loop completed.')
return y;
}
Alternatively, you may try using wrapper library like mysql-promise and promise-mysql
I have written the following code in Nodejs which is saving data in MongoDB:
function insertDoc(db,data){
return new Promise(resolve => {
callback=db.collection('AnalysisCollection').insertOne(data).then(function(response,obj){
console.log("Inserted record");
resolve(obj);
//console.log(obj);
// response.on('end',function(){
// resolve(obj);
// });
//return resolve(obj);
}).then(() => { return obj }
).catch(function(error){
throw new Error(error);
});
})
}
I am calling the above function from the main function like this:
async function cosmosDBConnect(nluResultJSON){
try{
//console.log("Inserting to cosmos DB");
console.log(nluResultJSON);
var url = config.cosmos_endpoint;
var result="";
var data = JSON.parse(JSON.stringify(nluResultJSON));
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
var db = client.db('NLUAnalysisDB');
// insertDoc(db, data, function() {
result=insertDoc(db, data, function() {
console.log(result);
client.close();
//return data._id;
});
});
}
catch (e) {
console.log(e);
}
}
module.exports = { cosmosDBConnect };
But in cosmosDBConnect, I am getting 'undefined' for the result, though in insertDoc I am getting the output for'obj' with _id for the inserted record.
Please help me to return this _id to cosmosDBConnect.
You are use callbacks inside of async function, which creates internal scopes. So your return aplies to them instead of whole function. You should use Promise-based methods inside of async function using await (without callbacks) or wrap whole function into own Promise otherwise.
Example:
function cosmosDBConnect(nluResultJSON) {
return new Promise((resolve, reject) => {
var url = config.cosmos_endpoint;
var result = '';
var data = JSON.parse(JSON.stringify(nluResultJSON));
MongoClient.connect(url, function(err, client) {
if (err) return reject(err);
assert.equal(null, err);
var db = client.db('NLUAnalysisDB');
insertDoc(db, data).then(obj => {
console.log(obj);
client.close();
return resolve(data._id);
});
});
});
}
Also you need to understand that your insertDoc return Promise and do not accept callback you tried to pass.
Ref: async function
result = insertDoc(db, data).then((data) => {
console.log(data);
}).catch(err => console.error(err));
I've been struggling to figure out how to do this for the past two hours. But I can't seem to get the Promise to wait for my searchFacesFunc to complete before it solves. What is the correct way to do so?
async function searchFacesFunc(faceId){
var searchFacesParams = {
CollectionId: "my-collection",
FaceId: faceId,
FaceMatchThreshold: 80,
MaxFaces: 10
};
await rekognition.searchFaces(searchFacesParams, function(err, data) {
if(err){
throw err;
}else{
var matching_percent = data.FaceMatches[0].Similarity;
console.log('Matching Percent: ' + matching_percent);
}
});
}
return new Promise((resolve, reject) => {
rekognition.indexFaces(indexParams, function(err, data) {
if(err){
throw err;
}else{
const faceRecords = data.FaceRecords;
for(let i = 0; i < faceRecords.length; i++){
var faceId = faceRecords[i].Face.FaceId;
console.log('FaceId: ' + faceId);
searchFacesFunc(faceId); //The promise is finished before these multiple functions finish
}
resolve(null, 'success');
}
});
});
If the rekognition.indexFaces function accepts an asynchronous callback, you can solve this issue easily:
return rekognition.indexFaces(indexParams, async (err, data) => {
if (err) {
throw err;
} else {
const faceRecords = data.FaceRecords;
for (let i = 0; i < faceRecords.length; i++) {
var faceId = faceRecords[i].Face.FaceId;
console.log("FaceId: " + faceId);
await searchFacesFunc(faceId); // Await the promise
}
return "success";
}
});
};
However, if this is not the case, you can still solve this the following way:
Use util.promisify to "promisify" the rekognition.indexFaces function
Construct a recursive callback function that only resolves the original promise you constructed when it executed faceRecords.length times.
not able to get items. it return [] . but it show correct on console.log(item). i think before my map() runs complete. it print all data. how to solve this issue. i am new in node.
function getBlockUsers() {
return new Promise(function (resolve, reject) {
BlockUser.find({userId:req.user._id}).populate("blockedId").lean().exec(function (err,result) {
if(err){
reject({"msg":"failed to getting block user."})
}else{
var results = [];
result.map(function(item){
Vehicle.findOne({userId:item.blockedId}).lean().exec(function(err,vehicle){
if(vehicle){
item.vehicleId = vehicle._id;
item.vehicleModel = vehicle.model;
}
results.push(item)
console.log(item)
});
});
resolve(results);
}
})
});
}
Because you use an async function in the map function wish is synchronous you need to create an array of promise and use Promise.all before the resolve to wait for all the results.
The code bellow should fix your issue.
function getBlockUsers() {
return new Promise(function (resolve, reject) {
BlockUser.find({userId:req.user._id}).populate("blockedId").lean().exec(function (err,result) {
if(err){
reject({"msg":"failed to getting block user."})
}else{
var results = result.map(function(item){
// don't forget to return in the map function
return new Promise(function (resolve1, reject1) {
Vehicle.findOne({userId:item.blockedId}).lean().exec(function(err,vehicle){
if (err) return reject1(err)
if(vehicle) {
item.vehicleId = vehicle._id;
item.vehicleModel = vehicle.model;
}
resolve1(item)
});
})
});
// here you wait all the promises of results
resolve(Promise.all(results));
}
})
});
}
The problem is you have non-blocking code inside your result.map().
You should try using just one DB query. Then resolve all the items in the exec callback. Otherwise use a promise for the original query.
Vehicle.find({ $in: { userId: result.map( item => item.blockedId) }}).lean().exec( (err, results) => {
// add the vehicle / model ids to each item in results
resolve(results)
})
I'm wondering if the code I have written here is sane and follows the rule of non-blocking, I come from a Java background so I'm new to non-blocking event loop of Node.js.
retard.js:
var MongoClient = require('mongodb').MongoClient;
var retard = {};
retard.getDb = function (url) { // url example 'mongodb://localhost:27017/myproject'
return new Promise(function (resolve, reject) {
MongoClient.connect(url, function (err, db) {
if (err)
throw err;
// custom functions
db.getCollection = function (mCollection) {
var obj = {};
var collection = db.collection(mCollection);
// access to the native drivers
obj.native = collection;
obj.findOne = function (query) {
return new Promise(function (resolve, reject) {
collection.findOne(query, function (err, result) {
if (err)
throw err;
resolve(result);
});
});
};
return obj;
};
resolve(db);
});
});
};
module.exports = retard;
This would then be used as following:
var co = require('co');
var config = require('./config');
var retard = require('./lib/retard');
co(function* () {
var db =
yield retard.getDb(config.mongodb.url);
var countries = db.getCollection('countries');
// first query
var doc =
yield countries.findOne({
country: 'scotland'
});
console.log(JSON.stringify(doc));
// second query
countries.native.findOne({
country: 'scotland'
}, function (err, result) {
if (err)
throw err;
console.log(JSON.stringify(result));
});
});
I get the results I was expecting from the database so it works. I'm just curious as to is this ok JavaScripting?
Almost there! Something to keep in mind is that that mongodb driver methods already return a Promise if no callback is passed (findone).
Rather than wrapping the methods with a new Promise, you can just return the method itself (a Promise) as follows:
return collection.findOne(query)
as opposed to:
return new Promise(function (resolve, reject) {
collection.findOne(query, function (err, result) {
if (err)
throw err;
resolve(result);
});
});
Same applies to MongoClient.connect();