I have a few classes which use ‘dns’ from node.js. But when an error occurs, my app is thrown. I made a siimple example with classes and throwable functions and I faced with the same problem. It’s works if an exception is thrown from function but it doesn’t work if an exception is thorwn from class.
Example:
class Test {
constructor() {
this.t();
}
async t() {
throw new Error("From class");
}
}
async function test(){
new Test();
}
try {
test().catch(e => {
console.log("From async catch");
});
} catch (e) {
console.log("From try catch");
}
Output:
Uncaught (in promise) Error: From class
at Test.t (<anonymous>:6:11)
at new Test (<anonymous>:3:10)
at test (<anonymous>:11:3)
at <anonymous>:15:3
How to catch errors from try/catch block in this example?
UPD:
Full code (typescript):
export class RedisService {
client: any;
expirationTime: any;
constructor(args: RedisServiceOptions) {
let redisData: any = {};
if (args.password)
redisData["defaults"] = { password: args.password };
dns.resolveSrv(args.host, (err, addresses) => {
if (err) {
/// Handling error in main func
}
else {
log.info("Using Redis cluster mode");
redisData["rootNodes"] = addresses.map(address => {
log.info(`Adding Redis cluster node: ${address.name}:${address.port}`);
return Object({ url: `redis://${address.name}:${address.port}` })
});
this.client = createCluster(redisData);
};
this.client.on('error', (err: Error) => log.error(`Redis error: ${err.message}`));
this.client.connect().then(() => { log.info("Connected to Redis") });
});
this.expirationTime = args.expirationTime;
}
/// Class functions
}
3
Answers
Don’t make async methods)))
Your solution looks somewhat like this.
Have a nice rest of your day
You generate multiple async-requests but you can only catch errors from the first one:
You create a promise with
async function test()
.Then you create a syncronous call within it, with
new Test()
, every error syncronously thrown from within it will be catched by thecatch
.Then you generate another promise call from within the syncronous constructor, this error can’t be caught by the
try/catch
-block or.catch
at, or above theasync function test()
.It is similar to this:
So you have 3 possible ways to solve it:
async t() {}
-call.this.t().catch(console.error)
(which can’t be forwarded to the try/catch block) as it is forwarded to the catch block of the Promise behind the async call. And if there is no.catch
on the async call, you get the "Unhandled Promise rejection"-Error.In particular, when an asynchronous error event occurs in the
constructor
, yes. Like your question title says, you can’t handle errors outside of anasync
context, and a constructor is not that.Your current implementation has many issues, from
client
beingundefined
until it is initialised to not being able to notify your caller about errors.All this can be solved by not putting asynchronous initialisation code inside a
constructor
. Create the instance only once you have all the parts, use anasync
helper factory function to get (and wait for) the parts.Now in your main function, you can call
create
, useawait
, and handle errors from it: