So basically I am trying to carry out function synchronously using next but Its not happening synchronously: Route.JS
router.post('/era',function(req,res,next){
console.log("got request");
controlleri.book(req,res,next);
booking_controller.book(req,res);
console.log("done in server.js");
next();
});
controlleri.book and booking_controller.book both have database calls but
Inspite of adding next() in controlleri.book, booking_controller.book starts executing before next being called in the first function.
Tell me if both functions are needed.
Edit:
Tried using async library still its not going synchrounosly Code:
router.post('/era',function(req,res){
console.log("got request");
async.series([
function(callback){
console.log("hi");
controlleri.book(req,res);
callback(null);
},
function(callback){
console.log("hias");
booking_controller.book(req,res);
callback(null);
}
]);
Second function begins before completing First one
Both of your functions take req, res and next as their arguments which is a signature for a middleware function. Further, express middleware is executed in order. Why not just make each of your functions into their own middleware and in the execution order you need them in?
// POST executes controlleri.book
// then booking_controller.book,
// then the log code
router.post('/era', controlleri.book, booking_controller.book, function(req, res, next) {
console.log("done in server.js");
});
This way, next within controlleri.book will be booking_controller.book, and next in booking_controller.book will be the last method that logs "done in server.js"
Use aync library for doinf operations syncronously.
next() is a middleware which tells that the request shouldn't be returned but there are more functions to be applied on the request.The functions it gets to operate are performed asynchronously because that's node's default behaviour.
async.series([
controlleri.book(callback){
// do some stuff ...
callback(null, 'one');
},
booking_controller.book(callback){
// do some more stuff ...
callback(null, 'two');
}
],
// optional callback
function(err, results){
// results is now equal to ['one', 'two']
});
async.series takes an array of functions to be performed in order (synchronously). The callback passed in each function is mandatory.
Related
I'm using nodejs with expressjs for my api.
I want to call a function after res.json() is called.
for example the api fetches data to the client but i want to log that action but no need to make client wait for request response till the api saves log
module.exports = {
getAll:async function(req,res){
////fetch data from db
res.json({success:true,data:data});
module.exports.logthis();
return;
},
logthis: async function ()
{
//save log
}
}
is this true that logthis will not be interupted after return; is called ?
also is there a better pattern to do this, like a event queue listener so that i threw that request in a pool and it's executed whenever it's possible ?
Sending a json response to the client or using return statement will not stop the script from executing logthis function only if you put return statement before it.
module.exports = {
getAll:async function(req,res){
//fetch data from db
res.json({success:true,data:data});
this.logthis(data);
return;
},
logthis: function (data) {
// log data to file here
}
}
Remember that async function works in conjunction with await statement, if you don't have asynchronous functions inside getAll there is no need to use async keyword
You can simply use callback or promise instead.
function (data, callback){
DB.find(........)
callback(err,data)
// Do other stuff here.
}
Use
res.json({success:true,data:data}).then(function(){
//Enter your code here. res.json() has finished.
});
I try to execute two functions in a post request but only one is triggered. The function makeEntry executes but the function afterwards renderEntries does'nt. Can anyone help pls?
Here is the code: https://codepaste.net/bpsxsy
This is due to how callbacks work in Javascript. Here is the part which matters:
app.post('/guestbook_post', urlencodedparser, function(req, res){
makeEntry(req, res, Guestbook);
renderEntries(res, Guestbook);
});
You pass res to both functions. But makeEntry invokes res.send() which means it will end the request and send the response back to the client. However, renderEntries was not yet executed, but still waiting in event loop. It will be executed the next time you make a post request, which will lead to very confusing and buggy behaviour.
To make it work as intendeed, refactor functions makeEntry and renderEntries to return the needed result object and render it to the client once. Something like this:
app.post('/guestbook_post', urlencodedparser, function(req, res){
makeEntry(req, Guestbook, (err, entry) => {
renderEntries(entry, Guestbook, (err, result) => {
res.send(result);
});
});
});
I have a function which resolves by taking a callback like function(error, result) { ... } as a parameter. I'm trying to use mocha to test this function, but the problem is that the function returns asynchronously, so there's no good place for me to put the done(). If I put inside my result handler, it takes too long and mocha times out. If I put it outside, the test always passes because the handler hasn't been called yet. Here is my code. What's the best way to get around this?
lbl.createLabels is a function that takes an array of customers, and a directory, and creates a bunch of files in that directory, and then asynchronously calls the callback of type: function(error, callback).
describe('Tests', () => {
it('returns a list of customer objects', (done) => {
lbl.createLabels(customers, __dirname + "/..", (err, result) => {
err.should.equal(undefined)
result.should.be.a('array')
result[0].should.have.property('id')
result[0].should.have.property('tracking')
result[0].should.have.property('pdfPath')
const a = {prop:3}
a.prop.should.be.an('array')
done() // putting done() here results in a timeout
})
done() // putting done here results in the test exiting before the callback gets called
})
})
Mocha's documentation has an entire section describing how to test asynchronous code:
https://mochajs.org/#asynchronous-code
Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named done) to it(), Mocha will know that it should wait for this function to be called to complete the test.
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(function(err) {
if (err) done(err);
else done();
});
});
});
});
The following question is asked in order to better understand from your answers how to think "Async" when developing on Node.js
I have the following code:
router.get('/', function(req, res, next) {
... //Definition of rules and paramsObj
//Validation that returns a promise
Indicative.validate(rules,paramsObj)
.then(function(success){
//we passed the validation. start processing the request
//ProcessRequest has async calls but when all async functions are over, it sets paramObj.someVal with a calculated value.
processRequest(paramsObj,next);
//My problem is here. at this point paramsObj.someVal is not set yet. and therefore the response to the user will be incorrect.
res.send(paramsObj.someVal);
}).catch(function(err){
console.log(err);
next(err);
}).done();
}
I wish to understand how to better think "async" while i need to wait with the response to the user until all async functions are over.
My question is how to execute res.send(paramObj.someVal) only after the paramObj.someVal is set by some async methods in processRequest(paramsObj,next);
If you need to wait on the result of processRequest for paramsObj.someVal to be set then ultimately you need to handle that callback
router.get('/', function(req, res, next) {
... //Definition of rules and paramsObj
//Validation that returns a promise
Indicative.validate(rules,paramsObj)
.then(function(success){
//we passed the validation. start processing the request
//ProcessRequest has async calls but when all async functions are over, it sets paramObj.someVal with a calculated value.
processRequest(paramsObj, function(err) {
if (!err && !paramsObj.someVal) {
// raise a custom error if the value is not set
err = new Error('Value not set');
}
if (err) {
next(err);
} else {
res.send(paramsObj.someVal);
}
});
}).catch(function(err){
console.log(err);
next(err);
}).done();
}
Assuming the second argument to processRequest() is a completion callback, you can pass your own function for that callback and do your res.send() in that custom callback like this:
router.get('/', function(req, res, next) {
... //Definition of rules and paramsObj
//Validation that returns a promise
Indicative.validate(rules,paramsObj)
.then(function(success){
//we passed the validation. start processing the request
//ProcessRequest has async calls but when all async functions are over, it sets paramObj.someVal with a calculated value.
processRequest(paramsObj,function() {
res.send(paramsObj.someVal);
});
}).catch(function(err){
console.log(err);
next(err);
}).done();
}
Since you do res.send(...), I assume you don't want to actually call next() in that code path.
Recently I switched from using callbacks to using promise in my rest api express app.
But I'm having trouble with unit testing routes/controller with async behaviour of the promise. Here is the sample code that needs to be unit tested.
var handler = function (req, res, next) {
var query = {},
var options = {
sort: { updatedAt: -1 },
limit: 10
};
if (req.query.before) {
query.updatedAt = { $lt: req.query.before };
}
// User.findAsync returns bluebird promise
User.findAsync(query, null, options).then(function (user) {
res.json(user);
}).catch(function (e) {
next(e);
});
}
router.get('/api/users', handler);
My approach to test above code was to spy on req, next, and User.findAsync and check if they are called with correct arguments. But because of async behaviour of the promise, I was having trouble to check if res.json or next are get called.
I've tried to stub findAsync to return resolved promise (Promise.resolve(user)). but still then callback is executed asynchronously.
I'm not sure if I'm on the right track for testing express application.
What is good strategy to test this kind of code in good separation?
I've also heard about using supertest.
But for me, Using supertest to test from http end point feels like more of integration testing which is not unit testing and is quite expensive.
Also, In general, I would like to know if it is good practice to try to cover all of the code with unit testing (models, controller, middleware, etc) and what's good strategies or techniques of doing that. Or If it is just good enough to test http end points with super test.
If your method being tested doesn't return a promise then you can't use the promise syntax in Mocha. You can test your method the same way you'd test any other asynchronous method - with done as a parameter of it. Let's say we want to test your handler function:
var handler = function (req, res, next) {
//...
User.findAsync(query, null, options).then(function (user) {
res.json(user);
}).catch(function (e) {
next(e);
});
}
We can write a test as such:
describe("The handler", function(){
it("calls res.json", function(done){ // note the done argument
handler({query: {before: 5}, // mock request
{json: done} // res.json calls our `done` param of this function
function(){ throw new Error("error called"); });
});
});
Note that we mocked the request, response and the next handler. Our mocked response has a json method that lets the test know it is complete (this can be a function if you want to make assertions inside it) and if next is called instead we throw to signal it's not something that was supposed to happen.