If you're starting out with the tutorial and get errors, you probably have seen them before:
(node:12741) UnhandledPromiseRejectionWarning: O noes, an error!
(node:12741) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:12741) [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.
which generally leads to a tricky error that lacks any useful information as to what actually caused the error. After all, the only thing you get is the error message.
So how can we solve this? The solution is the Promise method, catch, as it allows us to get the original stack trace of the original error. Whenever a method returns a Promise (read the documentation, as it will tell you!)
getPromise().catch(e => console.error('O noes, we got an error!', e);Scrapping the catch will cause the error we started with.
In your own code, you can accidentally return a promise without knowing: async functions. Ever use an async function? Make sure to call catch on whatever calls it. For example:
// Example taken from Discord bots
client.on('message', () => {
// Assume this is an async function like
// let foo = async () => {...}
foo();
}Will throw the error you hate and detest (again, the one we begin with). How do we deal with this? You should know by now :)
// Example taken from Discord bots
client.on('message', () => {
// Assume this is an async function like
// let foo = async () => {...}
foo().catch(e => console.error(e)); // Print the error to the console
}Now that pesky error will turn into a proper stack trace.
Error: O noes!
at foo (repl:4:11)
at repl:1:1
at Script.runInThisContext (vm.js:65:33)
at REPLServer.defaultEval (repl.js:246:29)
at bound (domain.js:370:14)
at REPLServer.runBound [as eval] (domain.js:383:12)
at REPLServer.onLine (repl.js:497:10)
at REPLServer.emit (events.js:165:20)
at REPLServer.Interface._onLine (readline.js:287:10)
at REPLServer.Interface._line (readline.js:640:8)
Telling us it was thrown from the 4th line of whatever defined foo (in this case, as it's from the node repl, the line numbers start at let foo = ... and end at the closing brace - in your file, it'll be the actual line number).
Another way to deal with promises, is awaiting them. This returns the value of the promise rather than having to use the then method. If an error is thrown, it'll rethrow this, so you can just use try-catch as you're used to. Nice, huh?
Of course, this come with a down side: the caller has to be async as well, leading to a lot of async methods in your code. Now, this isn't the biggest issue: even methods exposed to frameworks you use will become async, which is where the problem starts.
What if the framework doesn't expect an async function? It'll simply call the method and throw the Promise away! We'll get back to that pesky error again!
So how will we deal with this? Sadly, it means we cannot just use async whenever we please. Instead of making a function async, instead, use the pre-async await then & catch style to deal with the asynchrony (so Promise.prototype.then and Promise.prototype.catch)! That will be all you need to get rid of this error for good! (at least, as long as you don't managed to break this instead ;))
Only use async functions if you're able to catch it's errors. If you pass a function to a framework or library, and it doesn't deal with errors, don't make it async! Instead, deal with all promises yourself.
thx that is useful