在 javascript 的 async 函数中,使用 try...catch 块包裹 await 表达式是处理异步错误的标准做法。当 await 后面的 promise 被拒绝(rejected)时,程序会立即跳出当前执行流并跳转到 catch 块,此时 catch 接收到的参数就是 promise 的拒绝原因。如果 promise 正常解决(resolved),则代码进入 try 块继续执行后续逻辑。

await 抛出异常时的基本流程是怎样的
当 await 等待的 Promise 状态变为 rejected 时,JavaScript 引擎会将该拒绝值作为异常抛出。try 块中的代码在遇到这个异常时会停止执行,控制权直接转移给对应的 catch 块。这种机制允许开发者像处理同步错误一样处理异步错误,无需手动检查 Promise 的状态或链式调用 .catch()。

async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Data received:', data);
} catch (error) {
console.error('Failed to fetch data:', error.message);
}
}
上述代码展示了标准的错误处理模式。fetch 请求可能因为网络问题或服务器返回非 200 状态码而失败。通过 try...catch,我们可以统一捕获这些错误并进行日志记录或用户提示。注意,只有在 await 关键字处发生错误才会触发 catch,try 块内其他同步代码的错误同样会被捕获。
多个 await 语句如何分别处理错误
如果在同一个 try 块中包含多个 await 语句,任何一个 await 抛出错误都会导致整个 try 块中断并进入 catch。若需要独立处理每个异步操作的错误,应将每个 await 放在独立的 try...catch 块中。这样可以确保前一个操作的失败不会阻止后续操作尝试执行,或者允许对不同阶段的错误进行差异化处理。

async function processMultipleSteps() {
try {
const step1Result = await stepOne();
console.log('Step 1 completed');
} catch (error) {
console.error('Step 1 failed:', error);
// 可以选择在这里重试或退出
return;
}
try {
const step2Result = await stepTwo(step1Result);
console.log('Step 2 completed');
} catch (error) {
console.error('Step 2 failed:', error);
// 处理第二步特有的错误
}
}
这种写法将每个异步步骤隔离开来。第一步失败后,程序记录错误并可能提前返回,从而避免执行依赖于第一步结果的第二步。如果第一步成功但第二步失败,第二步的错误会被其自身的 catch 块捕获,不会影响第一步的结果。这种方式提供了更细粒度的错误控制。
Promise.allSettled 与 try-catch 的区别是什么
当需要并行执行多个异步操作且希望所有操作都尝试完成时,可以使用 Promise.allSettled。与 try...catch 不同,Promise.allSettled 不会因为某个 Promise 被拒绝而抛出异常,而是返回一个包含所有 Promise 结果的对象数组。每个结果对象都有 'status' 属性,值为 'fulfilled' 或 'rejected',以及对应的 'value' 或 'reason'。这使得可以在所有操作完成后统一检查哪些成功、哪些失败,而不是在第一个失败时立即中断。
async function runParallelTasks() {
const tasks = [taskA(), taskB(), taskC()];
const results = await Promise.allSettled(tasks);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Task ${index} succeeded with value:`, result.value);
} else {
console.error(`Task ${index} failed with reason:`, result.reason);
}
});
}
在这个例子中,即使 taskA 失败,taskB 和 taskC 仍然会执行。最终结果数组包含了所有任务的状态。这与 try...catch 的行为形成对比:如果使用 try...catch 包裹 Promise.all([taskA(), taskB(), taskC()]),那么只要有一个任务失败,就会立即抛出异常,其他未开始的任务可能会被取消或不再执行(取决于具体实现)。因此,选择哪种方式取决于业务逻辑是需要“快速失败”还是“全部尝试”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











