Await Receiving Warning while in try-catch Block - javascript

The first await below generates the warning 'await' has no effect on the type of this expression if I do not include the .catch line immediately found after (and currently commented out). However, all the code is included in a try-catch block. Why am I receiving this warning? Isn't the MongoClient.connectan asynchronous call?
const db = null
async function dbConnect() {
try {
const client = await MongoClient.connect(url, {useUnifiedTopology: true})
// .catch(err => { console.log(err) })
if (!client) throw new Error("Database Not Available")
db = await client.db(dbName)
} catch (err) {
console.log(err)
}
}
dbConnect()

.connect() returns a promise not a client. Try this code:
const db = null
async function dbConnect() {
try {
const client = new MongoClient(url)
await client.connect({useUnifiedTopology: true})
db = await client.db(dbName)
} catch (err) {
console.log(err)
}
}
dbConnect()

Related

Best way to use asyn/await in the following code

I am kind of new in Javascript and I want to connect to DB and run a script. Then get the result of script and run functions in order.
If there is any error with one of the functions, it should stop and doesnt run other functions.
I tried the following:
const {
Client
} = require('pg')
const client = new Client({
'connection info'
})
client.connect()
.then(() => console.log('DB connected'))
.catch(err => console.error('connection error', err.stack))
let dbResult
const data = async() => {
try {
dbResult = await client.query('SCRIPT') // array of json
} catch (error) {
console.log(error);
}
}
const func1 = async() => {
try {
// do something with dbResult
console.log('func1 success msg')
} catch (error) {
console.log('error in func1')
}
}
const func2 = async() => {
try {
// do something with dbResult
console.log('func2 success msg')
} catch (error) {
console.log('error in func2')
}
}
const func3 = async() => {
dbResult.forEach(result => {
// do something
})
try {
// do something with dbResult
console.log('func3 success msg')
} catch (error) {
console.log('error in func3')
}
}
data()
func1()
func2()
func3()
All the functions you call are async, therefore return Promises and should be awaited. You can await all of them in a try/catch block, so if one fails, the others won't execute.
Don't use try/catch in each individual function, but rather here :
const data = async() => client.query('SCRIPT') // array of json
const func1 = async() => console.log('func1 success msg')
const func2 = async() => console.log('func2 success msg')
const func3 = async() => dbResult.forEach(result => console.log(result))
(async () => {
try{
await client.connect();
let dbResult = await data();
dbResult = await func1(dbResult);
await func2();
await func3(dbResult);
} catch(err) {
console.log(err);
}
})();
await Promise.all([data, func1, func2, func3]) would also fail if one of the Promises failed, but does not guarantee the execution order.
Below is if you must use try catch inside each of your function body. If not, then I'd stick with the answer from Jeremy above.
What you can do is instead of console logging your errors that you receive in try..catch block, you can throw new error, which will stop the execution of your code and console log the actual error.
(Well, not exactly console log, but rather console.error() it)
This will prevent the execution of other functions, unless you do something with your error (make some error handling where you can execute another code, depending on the error).
In general, the syntax for this as follows:
try {
await someStuff();
} catch (err) {
throw new Error(err)
}
Object err has some additional properties, such as name and message.
Here is more about Error object.

node.js - get value of promise

let { errors } = otherValdations(data);
withDB(async (db) => {
return Promise.all([
..code...
]).then(() => {
return {
errors,
isValid: isEmpty(errors),
}
})
}, res).then((result) => {
console.log(result);
})
How can I get 'result' variable to be the value of the object returned in promise.all? This is the code for withDB function:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('app');
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error});
}
};
You need to modify withDB() so that it returns the value you want:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('app');
let result = await operations(db);
client.close();
return result;
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error});
throw error;
}
}
In your catch() handler, you also need to do something so that your calling code can distinguish the error path where you've already sent an error response from the case where you're resolved with the value. I don't know exactly how you want that to work, but I put in a throw error so that it will reject the returned promise and the caller can see that.
I notice from your error handling that you are assuming all possible errors are causing by an error connecting to the DB. That is not the case here. If operations(db) rejects, that will also hit your catch.
Promise.all returns an array with the results. So you either have to loop over the results or access them directly by supplying an index.

UnhandledPromiseRejectionWarning in Express App

I'm currently learning Javascript/Node.js/MEAN stack and I'm following an Express tutorial.
I get the following error:
(node:11524) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'close' of undefined
(node:11524) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
When I hit this route in my browser.
function router(nav) {
adminRouter.route('/')
.get((req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
(async function mongo() {
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
}
client.close();
}());
});
return adminRouter;
}
Could someone point out the issue and explain what the issue is please.
If this line rejects:
client = await mongoClient.connect(url);
Then, you go to your catch block and after that catch block, you call client.close(). But, client is undefined so client.close() will throw and you are not inside any sort of try/catch at that point. Since you're inside an async function, that throw will turn into a rejected promise which you have no .catch() to handle. Thus, you end up with an unhandled promise rejection.
You should be able to fix it like this:
function router(nav) {
adminRouter.route('/').get(async (req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
// make sure and send some response on errors
res.sendStatus(500);
}
if (client) {
client.close();
}
});
return adminRouter;
}
This makes several changes:
Add if (client) before calling client.close() to protect it from the case where `client never got set.
Make the whole .get() callback be async rather then using an IIFE (not required, just seems cleaner to me)
Send an error status and response in your catch statement so you are always sending an http response of some kind, even in error situations.
If you really wanted to be fail-safe, you could just add another try/catch:
function router(nav) {
adminRouter.route('/').get(async (req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
// make sure and send some response on errors
res.sendStatus(500);
}
try {
if (client) {
client.close();
}
} catch(e) {
console.log("unable to close database connection");
}
});
return adminRouter;
}

Properly terminate NodeJS Async Await

I wrote the following code to connect to MongoDB wrapped in a Promise, but as soon as it is connected, my NodeJS code is still running / not exit properly. May I know what is the proper way to return or terminate it?
function connectDB() {
return new Promise (resolve => {
MongoClient.connect(mongoUrl, function( err, db ) {
_db = db;
resolve(db);
});
})
}
(async function crawl() {
const db = await connectDB();
console.log('You are connected');
})()
This isn't really related to async/await, it also happens without. As #Torazaburo stated in the comments, the db driver maintains an open connection to the database, and this open socket (along with its eventhandlers) prevents node from quitting. Closing the connection helps:
function connectDB() {
return new Promise (resolve => {
MongoClient.connect(mongoUrl, function(err, db) {
if (err) reject(err);
else resolve(db);
});
});
}
(async function crawl() {
const db = await connectDB();
console.log('You are connected');
db.close();
console.log('You are no longer connected. Bye!');
})()
A promise have 2 paramaters: resolve and reject.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You need to change your promise declaration:
return new Promise ((resolve, reject) => {
// ...
}
After that, add return statement to your promise:
return resolve(db)
Also, i suggest you to add an error log to your promise:
if (err) return reject(err)
And catch this error.
Good luck!

this await throwing unexpected token error

I have a simple async function. It just sends a request and returns the data:
export const updatePanorama = async ({ commit }, payload) => {
const urlEnd = '/v1/pano/update'
const type = 'post'
const resp = await api.asyncRequest(urlEnd, type, payload)
commit('SET_PANORAMA', resp.data)
return resp
}
And this is how I'm using the function:
handleUpdatePanorama (panorama) {
const payload = {}
this.updatePanorama(payload).then(resp => {
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
}).catch(() => {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
},
The problem is, the code after catch runs if there's an error inside then. But this way I don't know whether the catch error is an request error or and error triggered by the code inside then.
I'm trying try and catch to solve that problem:
handleUpdatePanorama (panorama) {
try {
const payload = {}
const resp = await this.updatePanorama(payload)
console.log('resp:', resp)
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
} catch (err) {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
},
However, I get an unexpected token error in this line: await this.updatePanorama(payload)
What am I doing wrong?
The problem is, the code after catch runs if there's an error inside then
The solution for that is to not use catch, but the second then parameter. Have a look at the difference between .then(…).catch(…) and .then(…, …) for details.
I'm trying try and catch to solve that problem
That won't work, the catch clause will still be called if there's an exception thrown by setIsLoading or handleAlert.
I get an unexpected token error. What am I doing wrong?
You have not declared the handleUpdatePanorama method as async.
To mitigate the issues and fix the syntax, you could write
async handleUpdatePanorama (panorama) {
var result
try {
const payload = {}
const resp = await this.updatePanorama(payload)
console.log('resp:', resp)
result = ['updateSuccess', 'success']
} catch (err) {
result = ['updateError', 'danger']
} finally {
this.setIsLoading(false)
}
this.handleAlert(...result)
},
If you need to handle errors specifically from updatePanorama, use the second argument to .then(onSuccess, onError)
handleUpdatePanorama(panorama) {
const payload = {}
this.updatePanorama(payload).then(resp => {
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
}, err => {
// handle error from updatePanorama
// you can throw err if you also want to handle the error in .catch()
}).catch(() => {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
}
note: if you return (or have no return statement) from the error handler, any subsequent .then(onSuccess will execute, if you throw an error (or return Promise.reject() for example, then the .catch() code will also run

Categories

Resources