await with promise inside try/catch - node.js

For example, I have following function:
public static async getUser(userId: number): Promise<UserModel> {
try {
const permissions: PermissionsModel[] = await this.getPermissions(userId);
const userWithRelation: UserModel[] = await this.findUsers(userId, permissions);
return Promise.resolve(userWithRelation);
} catch (e) {
return Promise.reject(e);
}
}
Now, WebStorm warns me that I should put await before Promise.resolve() in try and catch block. I'm pretty new with Node, so should I put await or not and why?
Note: This is just example function, not the real code which I can't publicly show.

If an awaited Promise rejects, its reject value will be what the error in the catch handler is. If it resolves, the value the awaited Promise is assigned to will be the resolve value. So, your code can be simplified to the following:
public static async getUser(userId: number): Promise<UserModel> {
return this.findUsers(userId);
}
awaiting a Promise whose resolve value will be returned immediately, and whose rejection will be returned as a rejected Promise, is superfluous - just return the Promise itself.

I'm not sure about the warning, but you can shorten your code to
public static async getUser(userId: number): Promise<UserModel> {
try {
return this.findUsers(userId);
} catch (e) {
// Do something with the error
return Promise.reject(e);
}
}
If your're not doing anything else in the catch block, then you can actually just omit it and reduce your function to
public static async getUser(userId: number): Promise<UserModel> {
return this.findUsers(userId);
}

Promise and async/await are two different syntax's for asynchronous programming. What WebStorm is warning you about is that since you are using await inside async function, then await should be the thing to be returned from async function and not resolved Promise. You should choose to use either async/await syntax or Promise. You can see the difference on MDN's site:
For async/await: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
For Promises: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Related

Mark an asynchronous service function as asynchronous later in the controller

I have learned that a function with an asynchronous call (e.g. query to a database) is marked as await and the whole function block as async. However, I can apparently define some asynchronous functions without await and call them later with await (in my controller) and for others I am forced immediately to use await in my service class (VSC editor).
I have a user service class with CRUD operations. I can define findOne(), create() and find() without await, even though they perform asynchronous operations. In the controller I use them with async-await and I don't get an error from VSC even if I forget it. However, I have to use my update() and remove() functions in my service class with await because VSC shows me an error and says that I am missing await. Why do the update() and remove() functions have to be immediately marked with await and the others three do not? The functions save(), findOne() and find() have the same Promise return value as my other two functions and access the same repository.
My code (service class):
#Injectable()
export class UsersService {
constructor(#InjectRepository(User) private repo: Repository<User>) {}
create(email: string, password: string) {
const user = this.repo.create({ email, password });
return this.repo.save(user);
}
findOne(id: number) {
return this.repo.findOne(id);
}
find(email: string) {
return this.repo.find({ email });
}
async update(id: number, attrs: Partial<User>) {
const user = await this.findOne(id);
if (!user) {
throw new NotFoundException('user not found');
}
Object.assign(user, attrs);
return this.repo.save(user);
}
async remove(id: number) {
const user = await this.findOne(id);
if (!user) {
throw new NotFoundException('user not found');
}
return this.repo.remove(user);
}
}
Where is the difference and should I then rather always mark all my CRUD operations in the service class immediately as async-await in order to be able to call them later in the controller without async-await?
PS: Sorry if my text is still written too confusing. Why do I have to write await this.findOne() in the function remove(), but I can use this function findOne() with this.repo.findOne(id) without await in the same class, although repo.findOne() is an asynchronous function?
You need to use await because you want the value resolved by the promise returned by this.findOne(id)
And this.repo.find() will return a promise as it's async, thus UsersService#findOne returns a Promise too. So:
return await this.repo.findOne(id) will behave the same as:
return this.repo.findOne(id)
Learn about async/await:
https://nodejs.dev/learn/modern-asynchronous-javascript-with-async-and-await
https://javascript.info/async-await
https://jakearchibald.com/2017/await-vs-return-vs-return-await

NestJs Async controller method vs calling await / async inside a method

I'm bit new to NodeJs & NestJs. I always wondered what's the difference between using async as the method return type inside a controller vs executing async operation inside a regular method ? How does NodeJs handles the request in both these cases if there is huge traffic on this API (eg. 40K req/min). Will it be blocking in the 2nd example and non blocking in the 1st or would it work in a similar way?
For Eg:
#Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
#Post()
async sample() {
return "1234";
}
}
vs
#Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
#Post()
function sample() {
return await methodX();
}
async function methodX(){
return "1234"
}
Please ignore what the content in sample() & methodX() does its only for example.
First, marking a method as async enables you to use the await keyword inside of it.
For example in the second sample you provided, you need to mark the method sample as async to await methodX:
#Post()
async function sample() {
// Now `await` can be used inside `sample`
return await methodX();
}
So to answer your questions
what's the difference between using async as the method return type inside a controller vs executing async operation inside a regular method ?
There is none. In both cases, the method of the controller will need to marked as async. Performing what the route is supposed to perform in the body of the method or extracting it in another async method is just a matter of code organisation.
Will it be blocking in the 2nd example and non blocking in the 1st or would it work in a similar way?
Both examples would work in a similar way.
Second, marking a mehthod as async doesn't actually make it async if there is no real async operation performed in its body like a request to another service or a setTimeout. It means that the following samples
// Sample 1
#Post()
async sample() {
return "1234";
}
// Sample 2
#Post()
function async sample() {
return await methodX();
}
async function methodX(){
return "1234"
}
Are both equivalent to the synchronous method
#Post()
syncSample() {
return "1234";
}
Finally, as stated by #Micael Levi, return await is syntactically correct but should be avoided. Considering this sample:
#Post()
function async sample() {
return await methodX();
}
async function methodX(){
throw new Error('something failed')
}
Because the method sample return await methodX, sample won't appear in the stack trace which makes debugging more difficult.
We would prefer this sample:
#Post()
function async sample() {
const result = await methodX();
return result;
}
async function methodX(){
throw new Error('something failed')
}

Error: Transaction rejected with non-error: undefined

I am using knex npm version 0.15.2. while Rollback the transaction I'm getting the following error:
Error: Transaction rejected with non-error: undefined
Trx.rollback()
above function used for rollback.
Same code working for knex version 0.12.6
This is the function I used for commit/Rollback.
function Commit(pTrx, pIsCommit, pCallback) {
try {
var co = require("co");
var q = require('q');
var Q = q.defer();
co(function* () {
if (pIsCommit) {
yield pTrx.commit();
} else {
yield pTrx.rollback();
}
Q.resolve(pCallback('SUCCESS'));
}).catch(function (error) {
Q.reject(pCallback(error));
});
return Q.promise;
} catch (error) {
console.log(error)
}
}
This code could use some work. :) Here are a few things that pop out:
You don't need co or q anymore. Promises and async/await are built-in and much simpler to use. Async functions automatically return promises that will be resolved with the value returned or rejected if an error is thrown. Learn about async/await here: https://jsao.io/2017/07/how-to-get-use-and-close-a-db-connection-using-async-functions/
You shouldn't return success as a string. If the function completes without throwing an exception, then success is implied. I see people do this from time to time, but it's often for the wrong reasons.
You shouldn't accept callback in a function that returns a promise, it should be one or the other. The caller of your function will either pass a callback or await it's completion.
If you are going to use callbacks, then you should return null as the first parameter when successful. See the last sentence here: https://nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/
Your function name, Commit, starts with an uppercase. This convention is typically used to indicate that the function is a contstructor function and meant to be invoked with the new keyword.
Here's how the function could look once cleaned up:
async function commit(pTrx, pIsCommit) {
// Not using a try/catch. If an error is thrown the promise returned will be rejected.
if (pIsCommit) {
await pTrx.commit();
} else {
await pTrx.rollback();
}
// Not going to return anything. If we get to this point then success is implied when the promise is resolved.
}
A consumer of your function would call it with something like:
async function myWork() {
// do work; get pTrx
try {
await commit(pTrx, true);
// If I get here, then I can assume commit was successful, no need to check a return value of 'SUCCESS'
} catch (err) {
// handle error
}
}
It's hard to say where the issue is with the code in its current state. However, if the issue truly is with Knex, then you should probably post this as an issue in the Knex repo: https://github.com/tgriesser/knex/issues But you should write a reproducible test case that proves its an issue with Knex.

Async Await Behaviour

A simple code to understand async/await is making me crazy.
I have a button on click on which i am reading some value from localstorage and showing it in an alert box. Before showing the alert i want to console.log the value.
If i understood async/await my code should d exactly that but it is working in reverse order. first the alert is coming and then the console.
//Method called on button click
findMyAge2() {
this.getData("age").then(result => {
console.log('Hi');
myAge2 = result;
});
alert(myAge2);
}
async getData(key): Promise<any> {
return await this.storage.get(`${key}`);
}
Expected Result:
in Console log :Hi
UI: Age
Actual Results:
UI: Age
in Console log :Hi
JavaScript is asynchronous by nature, so when you have a Promise returned, code continues execution and that Promise resolves some time afterward.
async/await is a way to control this flow of programming and can allow you to create Synchronous code that "awaits" the result of asynchronous execution.
Your problem here is that you want to return the promise from your getData function and await it in your findMyAge2 function.
async function findMyAge2() {
let result = await this.getData("age");
console.log('Hi');
myAge2 = result;
alert(myAge2);
}
async getData(key): Promise<any> {
return this.storage.get(`${key}`);
}
By adding async keyword to a function it will always now return a Promise. So you do not need to await in your return statement. That effectively does nothing. It would be like saying:
function getData(key) {
return new Promise(resolve => {
return localStorage.get(`${key}`).then(result => resolve(result))
})
}
You don't need to await that result in local storage because the consumer should be calling await or .then on the result regardless.
Try this way,
findMyAge2() {
this.getData("age").then(result => {
console.log('Hi');
myAge2 = result;
alert(myAge2);
});
}
async getData(key): Promise<any> {
return await this.storage.get(`${key}`);
}
Before you should wait to alert before data being retrieved.
async/await works like with promises, which means, code gets executed and you don't know when it will finish, you just know that after if finishes, you want something else to be executed.
This is exactly what you put inside the "then" function, which is what gets executed after the 1st part (asyc getData) gets executed.
In the case of your code, the findMyAge2 gets called when you click the button, then it executes the getData and specifies what happens after getting the result from that call, within the "then" block.
Therefore you just have to move the alert, into "then" block, then you'll have the result you expect.
var myAge2;
findMyAge2() {
this.getData("age").then(result => {
console.log('Hi');
myAge2 = result;
alert(myAge2);
});
}
async getData(key): Promise<any> {
return await this.storage.get(`${key}`);
}

Why does await function return pending promise

let request = require('request-promise')
function get(url) {
let _opt = {}
let response = (async () => {
try {
var ret = await request(url, _opt);
return ret;
} catch (e) {
console.log(e)
}
})();
return response
}
console.log(get('http://www.httpbin.org/ip'))
gives:
Promise { <pending> }
Why doesn't it wait for my response?
Why doesn't it wait for my response?
That's simple, because you are returning a promise. Node js is single thread and is executed in a non blocking way.
That means that return response in your get function is executed before the resolution of response variable.
Try as follow:
let request = require('request-promise')
function get(url) {
let _opt = {}
return request(url, _opt);
}
async function some () {
console.log(await get('http://www.httpbin.org/ip'));
}
some();
This example is also returning a promise, but in this case we are awaiting for the promise resolution.
Hope this help.
Async functions are non-blocking and will immediately return a promise rather than waiting for a result. This for example, allows for multiple async functions to run concurrently rather than each running sequentially.
To wait for a result, you can use the await keyword to block until the promise is resolved. The await command will return the result of the promise. For example, to log the result of the get function, you can change the last line to:
console.log(await get('http://www.httpbin.org/ip'))
UPDATE:
Let me give this one more try (sorry if I'm beating a dead horse here).
Since your response variable is an async function, it's return type is a promise by the definition of an async function. Even though the ret variable is await'ed, that just means that it will block while writing to the ret variable. The response async function needs to be run to completion in order for the await to complete. An await here would be useful if you wanted to wait for the return value and then add post-processing, but in this example specifically, your try block could simply be:
try {
return request(url, _opt)
}
Since request already returns a promise, the extra await is causing a trivial amount of overhead since it implicitly creates an extra promise.
Since response is a promise, and you are returning response, the function get is also returning a promise. You are then trying to log this promise (which obviously doesn't work). This is why you must await or .then the get function to get the result.
Source: https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8 under "Pitfall 1: not awaiting"

Resources