I have written a mocha test case for the async waterfall, "function2" is module which call for mongodb to get data, when i am trying to run the same code in node.js this async code works, but when i am do mocha test the "function2" call for mongodb throws error saying "[Error: Cannot determine state of server]".
i got to know the reason that the test is getting executed fast without waiting for mongodb to connect and return result.
can someone suggest me how to solve this problem. thanks in advance.
var function1 = require('../../method1');
var function2 = require('../../method2');
var function3 = require('../../method3');
describe('controller : ', function () {
it('should not return error', function (done) {
async.waterfall([
function(callback){
function1.method1(app.request, app.response, function(err,result) {
if(err){
callback(err,null);
}
else{
var var1 = result;
callback(null, var1);
}
});
},
function(var1, callback){
//Here I have a Mongodb Call
function2.method2(var1,function(err,result) {
if(err) {
callback(err,null);
}
else{
var var2= result;
var context = {
"c1": var1,
"c2": var2
};
callback(null, context);
}
});
},
function(context, callback){
function2.method2(context, function(err,result) {
if(err){
console.error(err);
callback(err,null);
}
else{
context.c3 = {};
result.forEach(function(e, i) {
for(var key in e) {
context.c3[key] = e[key];
}
});
callback(null, context);
}
});
},
function(context, callback){
should.exist(context);
}
],
function (err, result) {
should.not.exist(err);
should.exist(result);
});
});
});
I'm not sure but try to wait when connection (which use your module) is established.
before(function(done) {
connection.on('open', done);
});
Related
I have 3 function has to call in series one after the other. but first function is exeucting and in between second and third are executing.
var tasklist=[api_hit,delay,mysql_check];
if(task_list.length>0){
async.series(
tasklist,
function(err, response) {
console.log(err);
console.log(response);
results.data=response;
results.message="Completed";
console.log(results);
}
);
}
Internal functions:
function api_hit(callback){
console.log("Inside api");
var ele=task_list[0];
var apidata=[];
var msg={'data':[]};
apiinfo.forEach((item,key)=>{
if(item.Method_name==ele.Parameters){
//Here checking random Int value
if(item.Value=="{{$randomInt}}"){
item.Value = generate(25);
}
apidata.push(item);
}
});
var data=[];
data['api']=apidata;
apiModel.validateAPI(data,function(res){
console.log("result api");
msg.data=res;
msg.case='api_hit';
callback(msg);
});
}
function delay(callback){
console.log("Inside delay");
var msg={'data':[]};
global_vars.sleep(1000);
msg.data='success';
msg.case='task';
console.log("after delay");
callback(msg);
}
function mysql_check(callback){
console.log("inside mysql");
var ele=task_list[2];
var dbdata=[];
var msg={'data':[]};
dbchecks.forEach((item,key)=>{
if(item.query_id==ele.Parameters){
console.log(item.query+" ::: "+ele.Parameters);
dbdata.push(item);
}
});
data['dbdata']=dbdata;
apiModel.checkmysql(data,function(err,res){
if(err) throw err;
console.log("inside mysql res");
msg.data=res;
msg.case='task2';
callback(msg);
});
}
My intention is to call these function after completing of others and all the results has to process in a single variable. but in api_hit method when it is executing another function inside of it then delay()(second function of async) is executing. how to stop this and make it in sequence. thanks in advance.
The first argument to the callback function is the error, pass null in case of success.
'use strict'
const async = require('async')
function api_hit(callback) {
setTimeout(() => {
console.log('Completed api_hit')
callback(null, 'api_hit')
}, 1000)
}
function delay(callback) {
setTimeout(() => {
console.log('Completed delay')
callback(null, 'delay')
}, 100)
}
function mysql_check(callback) {
setTimeout(() => {
console.log('Completed mysql_check')
callback(null, 'mysql_check')
}, 500)
}
var tasklist = [api_hit, delay, mysql_check];
if (tasklist.length > 0) {
async.series(
tasklist,
function (err, response) {
console.log(err);
console.log(response);
}
);
}
Doc link: https://caolan.github.io/async/docs.html#series
i have above api in TestRouter.js
TestRouter.js
router.get('/all', function(req, resp) {
var data = reportBo.getAll();
console.log(data);
resp.status(200);
resp.send(data);
return resp;
});
i am calling getAll() from TestRouter.js to TestDao.js.
it is working fine and can fetch the data and can print in console. but i am trying to send this result to TestRouter.js and i am trying to print it on console. but it is showing undefined.
TestDao.js
module.exports.getAll = function () {
var connection = myDB.get();
connection.collection('REPORTS').find({}).toArray(function (err, result) {
if (err) {
throw err;
} else {
//console.log(result);
return result;
}
});
};
module.exports.getAll = function (callback) {
var connection = myDB.get();
connection.collection('REPORTS').find({}).toArray(function (err, result) {
if (err) {
callback(err);
} else {
//console.log(result);
callback(null, result);
}
});
};
And in your router:
router.get('/all', function(req, resp) {
reportBo.getAll(function(err, data){
if(err){
resp.status(500);
} else {
resp.status(200);
resp.send(data);
}
});
});
This way of doing things with callbacks is quite common in Node JS. Also, there is a better way called Promises. You can read up on it.
I am running a cron job with node with mongodb as the database. I am trying to close db connection and exit the process once the curr_1 each loop has executed completely.
However the exit() is called while function_2 is being executed. I understand this is due to the callback and is async in nature.
How do I make sure exit is called only once the curr_1.each is complete?
Any solution without promises?
function function_1(obj){
var curr_1 = coll_1.find({})
curr_1.each(function(err, doc) {
function_2(doc)
});
exit(obj)
}
function function_2(obj) {
coll_2.findOne({}, function(err, document) {
dosomeprocess(obj)
})
}
function exit(obj) {
// Close connection
console.log('closing connection')
obj.db.close();
process.exit();
}
It's a job for Node async....
For example:
async.each(
curr_1, // the collection to iterate over
function(doc, callback) { // the function, which is passed each
// document of the collection, and a
// callback to call when doc handling
// is complete (or an error occurs)
function_2(doc);
},
function(err) { // callback called when all iteratee functions
// have finished, or an error occurs
if (err) {
// handle errors...
}
exit(obj); // called when all documents have been processed
}
);
Without using any library:
function function_1(obj, callback) {
var curr_1 = coll_1.find({})
curr_1.each(function(err, doc) {
callback(err, doc);
});
}
function function_2(err, obj) {
coll_2.findOne({}, function(err, document) {
dosomeprocess(obj)
exit(err, obj);
})
}
function exit(err, obj) {
// Close connection
console.log('closing connection')
obj.db.close();
process.exit();
}
function_1(obj, function_2);
Using async module
var async = require('async');
async.waterfall([
function function_1(callback) {
var curr_1 = coll_1.find({})
curr_1.each(function(err, doc) {
if (err) {
callback(err, null)
} else {
allback(null, doc)
}
});
},
function function_2(obj, callback) {
coll_2.findOne({}, function(err, document) {
if (err) {
callback(err, null);
} else {
dosomeprocess(obj)
callback(null, obj);
}
})
}
], function done() {
obj.db.close();
process.exit();
});
Simply give a condition in your loop using counter.
function function_1(obj){
var curr_1 = coll_1.find({})
var curr_1Length = curr_1.length;
var counter = 0;
curr_1.each(function(err, doc) {
++counter;
//Check condition everytime for the last occurance of loop
if(counter == curr_1Length - 1){
exit(obj)
}
function_2(doc)
});
}
Hope it helps :)
I want to do async call from my getData function to getImage function but i am unable to get return data from getImage().Since the getData() does't wait for the completion of getImage(),as getImage() has further async db calls and therefore getData() always returns undefined.
What is the best way to do this instead doing nested callbacks?
var getData = function(id){
async.series([
function(callback){
var res = getImages(id);
callback(null, res);
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
console.log("Result: "+results);
}
});
}
var getImages = function(id){
async.series([
function(callback){
Image.find({id: id }).exec(
function(err, image) {
if (err) {
console.log(err);
callback(err, 0);
}else
{ console.log("Count: "+ image.length);
callback(null, image);
}
});
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
return results;
}
});
}
getData(1);
As you said you need to wait for getImages() to return, and you do that using promises.
Use any promise library, like q for instance:
var q = require('q')
...
var getImages = function(id){
var deferred = q.defer();
...
//do async logic that that evaluates some res obj you wish to return
db.find(..., function() {
deferred.resolve(res);
}
return deferred.promise;
}
Then, from getData(), you call it in the following matter:
getImages(id).then(
function(res) {
callback(null, res);
},
function(err) {
console.log("error:" + err);
}
);
As you are already using async - just use the waterfall functionality: https://github.com/caolan/async#waterfalltasks-callback
This way you will be able to run functions one after another and wait for the previous to finish, while still getting it's return value.
I'm using async waterfall and i've got a question about try/catch error.
I wan't to dodge this syntax method with one global try/catch and no duplicate a try/catch by function :
async.waterfall([
function (callback) {
try {
this.foo() // Ok
this.bar() // Method bar doesn't exist so without try/catch node will crash
} catch(ex) {
//print err
}
},
function (callback) {
try {
//Again & again
} catch(ex) {
//print err
}
}
//... function() with try catch ...
], function(err, result) {
//Do something
})
If you seek a more robust error handling system; try this:
var async = require('async');
function callbackErrorHandler(fn, callback) {
try {
fn()
} catch (err) {
callback(err);
}
}
async.waterfall([
function(callback) {
callbackErrorHandler(function() {
throw new Error('error1');
}, callback);
},
function(callback) {
callbackErrorHandler(function() {
throw new Error('error2');
}, callback);
}
],
//final
function(err, result) {
console.log(err);
});
/**
* Using Promises
*/
var async = require('async');
//promises
var Promises = require('bluebird');
function callbackErrorHandler(fn) {
return new Promises(function(resolve, reject) {
try {
resolve(fn()); //should return something
} catch (err) {
reject(err);
}
});
}
async.waterfall([
function(callback) {
callbackErrorHandler(function() {
throw new Error('error1');
})
.error(callback)
},
function(callback) {
callbackErrorHandler(function() {
throw new Error('error2');
})
.error(callback)
}
],
//final
function(err, result) {
console.log(err);
});
This script no longer print in final callback and crash node server :
Test this and try to rename test() by testt()
'use strict'
var async = require('./lib/node_modules/async')
function test()
{
console.log("hi !")
}
async.waterfall([
function(callback){
callback(null)
},
function(callback){
test()
callback(null, null)
}], function (err, result) {
if (err)
{
console.log("got an error !")
}
else
{
console.log("everyting is ok")
}
}
)