在异步上下文中尝试/捕获异步函数



我有几个类使用'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上下文之外处理错误,构造函数不是这样的。

你目前的实现有很多问题,从clientundefined,直到它被初始化,不能通知你的调用者有关错误。

所有这些都可以通过不将异步初始化代码放在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);
}
}

生成多个异步请求,但只能从第一个捕获错误:

  1. 使用async function test()创建承诺

  2. 然后在它内部创建一个同步调用,使用new Test(),从它内部同步抛出的每个错误将被catch捕获。

  3. 然后在同步构造函数中生成另一个promise调用,这个错误不能被try/catch块或.catch块捕获,或者在async function test()之上。

    类似如下:

    constructor() {
    new Promise(() => throw new Error(''))
    }
    

所以你有三种可能的方法来解决它:

  1. async t() {}-call中捕获错误。
  2. 你用this.t().catch(console.error)在构造函数中捕获它(它不能被转发到try/catch块),因为它被转发到async调用后面的Promise的catch块。如果async调用中没有.catch,你会得到"未处理的承诺拒绝"-错误。
  3. 不要在构造函数中调用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);
}
})();
}
}

祝你今天过得愉快

最新更新