我有几个类使用'dns'从node.js。但当错误发生时,我的应用程序被抛出。我用类和可抛出函数做了一个简单的例子,我遇到了同样的问题。如果从函数中抛出异常,它可以工作,但如果从类中抛出异常,它就不起作用。例子:
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");
}
输出:
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
如何在这个例子中从try/catch块捕获错误?
乌利希期刊指南:完整代码(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
}
如果从类抛出异常则不工作。
特别是在constructor
中发生异步错误事件时,是。就像你的问题标题所说的,你不能在async
上下文之外处理错误,构造函数不是这样的。
你目前的实现有很多问题,从client
是undefined
,直到它被初始化,不能通知你的调用者有关错误。
所有这些都可以通过不将异步初始化代码放在constructor
中来解决。只有在拥有所有部件后才创建实例,使用async
助手工厂函数来获取(并等待)部件。
export class RedisService {
client: RedisClient;
expirationTime: number | null;
constructor(client: RedisClient, expirationTime: number | null) {
this.client = client;
this.expirationTime = expirationTime;
}
static create(args: RedisServiceOptions) {
const addresses = await dns.promises.resolveSrv(args.host);
log.info("Using Redis cluster mode");
const redisData = {
defaults: args.password ? { password: args.password } : undefined,
rootNodes: addresses.map(address => {
log.info(`Adding Redis cluster node: ${address.name}:${address.port}`);
return { url: `redis://${address.name}:${address.port}` };
}),
};
const client = createCluster(redisData);
client.on('error', (err: Error) => log.error(`Redis error: ${err.message}`));
await this.client.connect();
log.info("Connected to Redis");
return new RedisService(client, args.expirationTime);
}
… // instance methods
}
现在在你的主函数中,你可以调用create
,使用await
,并从它处理错误:
async function main(){
try {
const service = await RedisService.create(…);
} catch(e) {
console.log("From async catch", e);
}
}
生成多个异步请求,但只能从第一个捕获错误:
-
使用
async function test()
创建承诺 -
然后在它内部创建一个同步调用,使用
new Test()
,从它内部同步抛出的每个错误将被catch
捕获。 -
然后在同步构造函数中生成另一个promise调用,这个错误不能被
try/catch
块或.catch
块捕获,或者在async function test()
之上。类似如下:
constructor() { new Promise(() => throw new Error('')) }
所以你有三种可能的方法来解决它:
- 在
async t() {}
-call中捕获错误。 - 你用
this.t().catch(console.error)
在构造函数中捕获它(它不能被转发到try/catch块),因为它被转发到async调用后面的Promise的catch块。如果async调用中没有.catch
,你会得到"未处理的承诺拒绝"-错误。 不要在构造函数中调用async函数,像这样使用它:
class Test {
async t() {
throw new Error("From class");
}
}
async function test(){
await (new Test()).t();
}
try {
test().catch(e => {
console.log("From async catch");
});
} catch (e) {
console.log("From try catch");
}
不要使用async方法
你的解决方案看起来有点像这样。
class Test {
constructor() {
this.t();
}
t() {
(async () => {
try {
throw new Error("From class");
} catch (e) {
console.log(e);
}
})();
}
}
祝你今天过得愉快