NodeJs Async await by default - node.js

Could be a bad practice to have all functions on a nodejs Express web app with async await syntax? (even if they not necessarily uses await methods) for example:
app.get(basePath, async function (req, res, next) {
await anyMethod().then(function () {
})
await anyMethod2().then(function () {
})
});
app.get(basePath, async function (req, res, next) {
anyMethod().then(function () {
})
});
The idea is to have allways defined like async for terms of templating or if I need to use them like this other example for best practices:
app.get(basePath, async function (req, res, next) {
await anyMethod().then(function () {
})
await anyMethod2().then(function () {
})
});
app.get(basePath, function (req, res, next) {
anyMethod().then(function () {
})
});
could be affect performance?
(I removed params and the logic of the promises for easy visualization of the question)

could be affect performance?
async/await impact always on performance.
If you add async in a synchronous function, you have a degradation of performance of 400%. A simple banchmark
Adding await in Node.js <= 11 create 2 Promises at the low level, one then wrap the upper code, and another one for the next literals.
With Node.js 12 await will produce only one additional Promise.
v8 and Node.js are working hard to reduce this impact on performance. V8 Article that explains how async/await works under the hood.
Looking your example, instead, it is not good because you are waiting for nothing:
await anyMethod2().then(function () { res.reply('hello') })
If you don't use the result of an await it is pointless because the output will be the same in the end:
await anyMethod2().then(function () { res.reply('hello') })
anyMethod2().then(function () { res.reply('hello') })
These two sentences produce the same result, but with different overhead (and error management).
And you have to think if anyMethod1() and anyMethod2() could be parallel or serial. In your example, you have lost the parallelism.
This is worth:
const res = await anyMethod2().then(function () { return {hi:'world'} })
res.reply(res)
If you await, use the output!

Related

i want to return array of posts, but i got an empty array

postsArr does not get data
router.get('/user-post/:id', checkJwt, (req, res, next) => {
let postsArr = []
db.userSchema.findOne({ _id: req.params.id })
.populate('posts')
.exec((err, da) => {
for (let i = 0; i < da.posts.length; i++) {
db.postSchema.find({ _id: da.posts[i]._id })
.populate('comments')
.exec((err, post) => {
postsArr.push(post)
})
}
console.log(postsArr)
})
})
This is a whole lot easier if you use the promise interface on your database:
router.get('/user-post/:id', checkJwt, async (req, res, next) => {
try {
let da = await db.userSchema.findOne({ _id: req.params.id }).populate('posts').exec();
let postsArray = await Promise.all(da.posts.map(post => {
return db.postSchema.find({ _id: post._id }).populate('comments').exec();
}));
res.json(postsArray);
} catch (e) {
console.log(e);
res.sendStatus(500):
}
});
The challenge with an asynchronous operation in a loop is that they don't run sequentially - they all run in parallel. The for loop just starts all your asynchronous operations and then you never know when they are all done unless you track them all somehow. That can be done without promises by using counters to keep track of when every single asynchronous result is done, but it's a whole lot easier to just let Promise.all() do that for you. It will also put all the results in the right order for you too.
If you wanted to sequence the database operations and run them serially one at a time, you could do this:
router.get('/user-post/:id', checkJwt, async (req, res, next) => {
try {
let da = await db.userSchema.findOne({ _id: req.params.id }).populate('posts').exec();
let postsArray = [];
for (let post of da.posts) {
let result = await db.postSchema.find({ _id: post._id }).populate('comments').exec();
postsArray.push(result);
}
res.json(postsArray);
} catch (e) {
console.log(e);
res.sendStatus(500):
}
});
This second version runs only one database operation at a time, sequentially. It will put less peak load on the database, but likely be slower to finish.
You will notice that the use of promises and await makes the error handling much simpler too as all errors will propagate to the same try/catch where you can log the error and send an error response. Your original code did not have error handling on your DB calls.

Nesting .then() and catch in Javascript promise

I'm not experienced with Javascript promises and recently I started using promises instead of callbacks in my Javascript projects.
When I tried to run several promise functions one after another I landed in a nested chaos of then(). The code works exactly as expected, but my question is that if this is the way to resolve several promise functions one after another then what is the advantage of using promises instead of callbacks.
If I'm not doing it the right way, then it is a request from you guys to show me the proper way of resolving nested promises.
Below is my code that I don't like it they way it looks:
exports.editExpense = (req, res, next) => {
Account.findAll().then(accounts => {
Budget.findAll().then(budgets => {
Expense.findAll().then(expenses => {
Expense.findByPk(id).then(expense => {
res.render('expenses/index', {
urlQuery: urlQuery,
expenses: expenses,
expense: expense,
accounts: accounts,
budgets: budgets
});
})
})
})
}).catch(error => console.log(error));
};
You can use async/await structure for better formatting
exports.editExpense = async(req, res, next) => {
try {
let accounts = await Account.findAll();
let budgets = await Budget.findAll();
let expenses = await Expense.findAll()
let expense = await Expense.findByPk(id);
if (expense) {
res.render('expenses/index', {
urlQuery: urlQuery,
expenses: expenses,
expense: expense,
accounts: accounts,
budgets: budgets
});
} else {
console.log('else') //<<- Render/Handle else condition otherwise server will hang.
}
} catch (error) {
console.error(error)
}
You should try to minimize the amount of async calls you make in a function as it will impact your performance.
If you prefer to use the then catch structure, in order to take fully advantage of it I recommend you not to nest them. Of course you can, but then you should put a .catch() after each of them. That's why the async introduction made an easier code to read and handle errors, as it simplifies it with the try catch structure.
If you pipe multiple .then(), you can return a value as a promise from each of them that can be used inside the next one once the promise resolves. The only thing is that you loose these values unless you save them either in req with new properties or in variables declared outside the pipe of .then().
That's why, in this snippet, I declared all the variables at the beginning in order to save all the values and use them in the final res
exports.editExpense = (req, res, next) => {
let accounts;
let budgets;
let expenses;
Account.findAll()
.then(fetchedAccounts => {
accounts = fetchedAccounts;
return Budget.findAll()
})
.then(fetchedBudgets => {
budgets = fetchedBudgets;
return Expense.findAll()
})
.then(fetchedExpenses => {
expenses = fetchedExpenses
return Expense.findByPk(id)
})
.then(expense => {
return res.render('expenses/index', {
urlQuery: urlQuery,
expenses: expenses,
expense: expense,
accounts: accounts,
budgets: budgets
});
})
.catch(error => console.log(error));
};

Best way to structure async Express GET request

I have been looking to update my Express skills by incorporating async/await handling and had a quick question.
From the examples I have seen online, most requests are structured wrapped inside of a try/catch block and add any await tasks to a variable before handling them.
app.post('/signup', async(req, res) => {
const { email, firstName } = req.body
const user = new User({ email, firstName })
const ret = await user.save()
res.json(ret)
})
My code looks like this:
app.route("/articles")
// GET: articles
.get(async (req, res) => {
await Article.find((err, results) => {
if (!err) {
res.json(results);
} else {
res.send(err);
};
});
})
Should I assign the response from my Mongoose to find to a variable as the first code block example and handle in a try/catch, or does my code essentially do the same thing and in a way that's the best practice as is?
Thanks in advance!
Cheers,
James
Be aware that there are two very different uses of the word async in javascript. The first is the general concept of asynchronous functions which can be implemented in any language and is widely used in javascript with various design patterns (callback, promises, async/await). The second is the async keyword which is used to allow the usage of await and only works on promises (does not work in callbacks).
You seem to be confusing the two. Because of this I now advise people not to use the word "async" when referring to asynchronous functions and only use it to refer to the async keyword.
Your function does not return a promise because you passed a callback to it. As such it cannot be used with await. Because you cannot use await it makes no sense to mark the function as async. I consider your code buggy even though it works - the mechanism still function (the await keyword conveniently ignores non-Promise functions like yours and does not generate an error) however it doesn't communicate your intent well and will confuse future maintainers of your code.
IMHO, the correct version of your code should be:
app.route("/articles")
// GET: articles
.get((req, res) => {
Article.find((err, results) => {
if (!err) {
res.json(results);
} else {
res.send(err);
};
});
})
The correct version of your code with async/await is:
app.route("/articles")
// GET: articles
.get(async (req, res) => {
try {
res.json(await Article.find());
}
catch (err) {
res.send(err);
}
})
The correct version of your code with promises but without async/await should be:
app.route("/articles")
// GET: articles
.get((req, res) => {
Article.find()
.then(result => res.json(result))
.catch(err => res.send(err));
})
The above is of course just my opinion but I suggest you strongly consider it a guideline. Any of the three forms above would be perfectly acceptable to most javascript programmers and most people consider which to use a matter of taste. Personally I prefer plain promises without await but async/await is useful when you have some tricky flow control logic.
Note that Mongoose conveniently supports both promises and callbacks so in this specific case you can just remove the callback to use async/await. However not all libraries do this. If you need to convert a callback based function to a promise you need to wrap it in the Promise constructor:
function convertedToPromise () {
return new Promise((resolve,reject) => {
callbackBasedFunction((err,result) => {
if (err) {
reject(err)
}
else {
resolve(result)
}
});
});
}

Is this async/await function writing to mongo collection before page redirect?

I have a route in express with a function that adds some req.body attributes info to a mongo collection. It works, but I’m not happy with it, it feels wrong to me, and I don’t think I’ve got my head around async/await yet.
This is the code:
router.post("/input/:id", ensureAuthenticated, async (req, res) => {
Project.findOne({
_id: req.params.id
}).then(project => {
const newInput = {
inputTitle: req.body.inputTitle,
inputValue: req.body.inputValue,
inputUnits: req.body.inputUnits,
inputCategory: req.body.inputCategory,
inputUser: req.user.id
};
// Add to the array, this is the async function
(async () => {
await project.inputs.unshift(newInput);
})();
project.save().then(project => {
res.redirect(`/projects/output/${project.id}`);
});
});
});
Is that async function doing what I think/hope it’s doing (I want it to add the newInput variable to the database before the page redirects)? What's the best way of doing this? Should I try and write it all as one function?

KOA / node.js outer function responds before callback finishes

First, I'm sorry for the title, I couldn't mind up something better.
I thought I understand Node.js / KOA, at least the basics but now I'm starting to feel that I'm missing some fundamentals.
Take a look at the following code:
router.put("/",
parse,
async function (ctx, next) {
// do something
await next();
},
async function (ctx, next) {
// do something
await next();
},
async function (ctx, next) {
if (some condition) {
gm(imageBuffer)
.quality(80)
.write(profile_path, async function (err) {
gm(imageBuffer)
.resize(60, 60)
.quality(80)
.write(chat_path,async function (err) {
await next(); // HERE 1
});
});
} else {
await next();
}
// HERE 2
},
async function (ctx, next) {
responses.success(ctx, "Success");
}
);
So what this is all about. The ones that are familiar with KOA framework will immediately see what is going on here. Where my problem starts/ends is in the third async function. So what I'm trying to do here is some image manipulation (saving). gm is asynchronus, but as you can see from the code I'm using anonymous callback functions, and what I'm trying to achieve is that the last async function is being called when gm finishes through await next(); // HERE 1.
But what really happens is (from my understanding)... gm starts asynchronously.. and // HERE 2 is hit, and because there's nothing, end of function, KOA returns default 404 response. I simply can't understand why this is so and how to overcome this.
What I really want to happen is when callback finishes await next(); // HERE 1 gets called and I can return success response.
await next(); // HERE 1 of course gets called (eventually) but too late, because KOA already responds with 404.
If there is someone that is able and willing to explain what exactly is happening here, thank you.
As far as I see is that your aproach is not really following the async await pattern: The async function should the "await" the asynchronous part. This then needs to return a promise. So you have to encapulate your callback in a promise. Something like this could work (not testet, just to show the concept):
function gmAsync(){
return new Promise(function(resolve,reject){
gm(imageBuffer)
.quality(80)
.write(profile_path, async function (err) {
gm(imageBuffer)
.resize(60, 60)
.quality(80)
.write(chat_path,async function (err) {
resolve(....whatever....);
});
});
});
}
and then you async function could look like this:
async function (ctx, next) {
if (some condition) {
await gmAsync()
next()
} else {
await next();
}
},
...
Makes sense?

Resources