Javascript 递归承诺触发 catch() 两次,很难跟进
Javascript recursive promise is firing the catch() twice, having a hard time following
我在 Discord.js v13 中编写了一个需要用户输入的函数。如果输入无效,需要重新提示一遍,原来的promise应该不再考虑了。
如果用户花费的时间超过 timeoutSeconds
,则会抛出 InputTimeout
错误。
实践中发生了什么,我不明白,是这样的:
- getResponse(...) 被执行
- 提示用户输入
- 用户提供了无效输入
- 用户被告知输入无效,并被重新提示
- 如果没有提供输入,第一个请求和会抛出一个
InputTimeout
错误 第二个 请求
我希望发生的是:
- getResponse(...) 被执行
- 提示用户输入
- 用户提供了无效输入
- 用户被告知输入无效,并被重新提示
- 如果未提供任何输入,则仅针对新请求抛出
InputTimeout
错误
这是我认为正在发生的事情...第二个提示抛出 InputTimeout
错误,导致第一个 Promise 中的 catch()
处理程序被触发。如果那是真的,那么我很困惑,因为我认为如果 then()
运行,那是因为没有抛出错误。那么为什么 catch()
从 then()
函数中捕获错误呢?应该把catch()
放在第一位,在then()
之前吗?这是我链接函数的顺序的问题吗?
async getResponse(user, timeoutSeconds, channel = null) {
if (channel == null) {
const msg = await user.send(this.promptMessage);
channel = msg.channel;
}
return await channel
.awaitMessages({
max: 1,
time: timeoutSeconds * 1000,
errors: ["time"],
})
.then(async (messages) => {
if (messages.size == 1) {
const message = messages.values().next().value;
if (this.validator(message)) {
await user.send(this.successMessage);
return this.formatter(message);
} else {
await user.send(this.errorMessage);
await this.getResponse(
user,
timeoutSeconds,
channel
);
}
}
})
.catch(async (e) => {
console.error(e);
await channel.send(this.timeoutMessage);
throw new InputTimeout();
});
}
问题实际上是 .then()
和 .catch()
的顺序。因为我只关心捕获来自 awaitMessages()
函数的错误,所以我应该首先将它链接到那个,然后是 .then()
.
通过将 catch()
放在 then()
之后,我从 then()
函数中捕获了错误。
哎呀!
新解决方案,也按照社区的建议删除了 .then()
和 .catch()
:
try {
let messages = await channel.awaitMessages({
max: 1,
time: timeoutSeconds * 1000,
errors: ["time"],
});
messages = Array.from(messages.values());
if (messages.length == 1) {
const message = messages[0];
if (message.author.bot) return;
if (this.validator(message)) {
await user.send(this.successMessage);
return this.formatter(message);
} else {
await user.send(this.errorMessage);
return this.getResponse( // note I removed "await" here to prevent nested errors
user,
timeoutSeconds,
channel
);
}
}
} catch (e) {
console.error(e);
await channel.send(this.timeoutMessage);
throw new InputTimeout();
}
我在 Discord.js v13 中编写了一个需要用户输入的函数。如果输入无效,需要重新提示一遍,原来的promise应该不再考虑了。
如果用户花费的时间超过 timeoutSeconds
,则会抛出 InputTimeout
错误。
实践中发生了什么,我不明白,是这样的:
- getResponse(...) 被执行
- 提示用户输入
- 用户提供了无效输入
- 用户被告知输入无效,并被重新提示
- 如果没有提供输入,第一个请求和会抛出一个
InputTimeout
错误 第二个 请求
我希望发生的是:
- getResponse(...) 被执行
- 提示用户输入
- 用户提供了无效输入
- 用户被告知输入无效,并被重新提示
- 如果未提供任何输入,则仅针对新请求抛出
InputTimeout
错误
这是我认为正在发生的事情...第二个提示抛出 InputTimeout
错误,导致第一个 Promise 中的 catch()
处理程序被触发。如果那是真的,那么我很困惑,因为我认为如果 then()
运行,那是因为没有抛出错误。那么为什么 catch()
从 then()
函数中捕获错误呢?应该把catch()
放在第一位,在then()
之前吗?这是我链接函数的顺序的问题吗?
async getResponse(user, timeoutSeconds, channel = null) {
if (channel == null) {
const msg = await user.send(this.promptMessage);
channel = msg.channel;
}
return await channel
.awaitMessages({
max: 1,
time: timeoutSeconds * 1000,
errors: ["time"],
})
.then(async (messages) => {
if (messages.size == 1) {
const message = messages.values().next().value;
if (this.validator(message)) {
await user.send(this.successMessage);
return this.formatter(message);
} else {
await user.send(this.errorMessage);
await this.getResponse(
user,
timeoutSeconds,
channel
);
}
}
})
.catch(async (e) => {
console.error(e);
await channel.send(this.timeoutMessage);
throw new InputTimeout();
});
}
问题实际上是 .then()
和 .catch()
的顺序。因为我只关心捕获来自 awaitMessages()
函数的错误,所以我应该首先将它链接到那个,然后是 .then()
.
通过将 catch()
放在 then()
之后,我从 then()
函数中捕获了错误。
哎呀!
新解决方案,也按照社区的建议删除了 .then()
和 .catch()
:
try {
let messages = await channel.awaitMessages({
max: 1,
time: timeoutSeconds * 1000,
errors: ["time"],
});
messages = Array.from(messages.values());
if (messages.length == 1) {
const message = messages[0];
if (message.author.bot) return;
if (this.validator(message)) {
await user.send(this.successMessage);
return this.formatter(message);
} else {
await user.send(this.errorMessage);
return this.getResponse( // note I removed "await" here to prevent nested errors
user,
timeoutSeconds,
channel
);
}
}
} catch (e) {
console.error(e);
await channel.send(this.timeoutMessage);
throw new InputTimeout();
}