Cleaner code
using async/await with Promise catch handler.
From what I see, this has been a long-standing problem that has bugged (both meanings) many programmers and their code. The Promise .catch is really no different from try/catch.
ES6 Promise's catch handler and work harmoniously with "await/async", providing a proper solution and cleaner code:
const createUser = await this.User
.create(userInfo)
.catch(error => console.error(error))
console.log(createdUser)
// business
// logic
// goes
// here
Note that while this answers the question, it gobbles up the error. In this case, it is better to throw because (1) this operation (creating a user) is not expected to failed, and (2) you not able to continue anyway -- the operation has errored out:
const createUser = await this.User
.create(userInfo)
.catch(error => {
// do what you need with the error
console.error(error)
// maybe send to Datadog or Sentry
// don't gobble up the error
throw error
})
console.log(createdUser)
// business
// logic
// goes
// here
Learning catch doesn't seem like worth it?
The cleanliness benefits may not be apparent above, but it adds up in real-world complex async operations.
As an illustration, besides creating user (this.User.create), we can push notification (this.pushNotification) and send email (this.sendEmail).
this.User.create
this.User.create = async(userInfo) => {
// collect some fb data and do some background check in parallel
const facebookDetails = await retrieveFacebookAsync(userInfo.email)
.catch(error => {
// we can do some special error handling
// and throw back the error
})
const backgroundCheck = await backgroundCheckAsync(userInfo.passportID)
if (backgroundCheck.pass !== true) throw Error('Background check failed')
// now we can insert everything
const createdUser = await Database.insert({ ...userInfo, ...facebookDetails })
return createdUser
}
this.pushNotifcation and this.sendEmail
this.pushNotification = async(userInfo) => {
const pushed = await PushNotificationProvider.send(userInfo)
return pushed
})
this.sendEmail = async(userInfo) => {
const sent = await mail({ to: userInfo.email, message: 'Welcome' })
return sent
})
Compose the operations:
const createdUser = await this.User
.create(userInfo)
.catch(error => {
// handle error
})
// business logic here
return await Promise.all([
this.pushNotification(userInfo),
this.sendEmail(userInfo)
]).catch(error => {
// handle errors caused
// by pushNotification or sendEmail
})
No try/catch. And it's clear what errors you are handling.
var, knowing the variable would be hoisted. Is that "wrong"?this.User.create()then you wouldn't put anything else inside the try/catch. But, it's also a perfectly reasonable design to put a whole bunch of logic inside a try block. It all depends upon how/where you want to handle an error and how you want to design your exception handling code and what makes sense for a given operation. There is no generic best practice. The ONE generic best practice is to make sure you catch and handle all errors in some appropriate way.async/awaitis part of ES2017 (this year's release), not ES6 (which was released two years ago).tryblock, and that codeErrors, (TypeError,ReferenceError, etc), that will becatched, which could produce unexpected behavior if you're expecting to onlycatchpromise rejections.