工作项目中使用async/await、$.when处理多AJAX调用的异常处理疑问
嘿,我来帮你搞定这个Vue.js里的async/await异常处理问题,结合你说的请求场景——前三个串行依赖、后三个并行独立,咱们一步步拆解,给你实用的代码方案:
一、先明确请求的执行逻辑
首先得把你的请求场景拆成两类:
- 串行依赖请求:前三个请求必须按顺序执行,每个请求的入参依赖上一个请求的返回结果,所以得用
await逐个等待请求完成。 - 并行独立请求:后三个请求互相不依赖,也和前三个无关,用
Promise.all可以同时发起,提升效率;如果需要容错(某个请求失败不影响其他),可以用Promise.allSettled或者给每个请求单独加异常捕获。
二、异常处理的核心思路
在async/await里,异常处理主要靠try/catch,但要根据需求选择捕获粒度:
- 整体捕获:用一个
try/catch包裹整个请求流程,适合只要有一个失败就终止流程的场景。 - 逐个捕获:给每个请求单独加
try/catch,适合需要对不同请求的错误做差异化处理的场景。 - 全局拦截:在Axios层面统一处理通用错误(比如401未授权、500服务器错误),减少组件里的重复代码。
三、具体代码实现(Vue.js示例)
假设你用的是Vue2 + Axios,以下是完整的组件内实现:
1. 串行依赖请求的异常处理
export default { data() { return { sequentialResults: [] }; }, methods: { async fetchSequentialData() { try { // 第一步请求:获取基础数据 const res1 = await this.$axios.get('/api/endpoint1'); const data1 = res1.data; // 第二步请求:依赖data1的参数 const res2 = await this.$axios.get(`/api/endpoint2/${data1.id}`); const data2 = res2.data; // 第三步请求:依赖data2的参数 const res3 = await this.$axios.get(`/api/endpoint3/${data2.key}`); const data3 = res3.data; // 保存所有串行请求结果 this.sequentialResults = [data1, data2, data3]; } catch (error) { // 捕获任意一步的异常 console.error('串行请求出错:', error); // Vue项目里常用的全局提示 this.$message.error('核心数据加载失败,请稍后重试'); // 针对特定错误做处理,比如未授权跳登录 if (error.response?.status === 401) { this.$router.push('/login'); } } } } };
如果需要对每个请求的错误单独处理(比如第一步失败就提示“基础数据加载失败”),可以给每个await单独套try/catch:
async fetchSequentialData() { let data1 = null; try { data1 = (await this.$axios.get('/api/endpoint1')).data; } catch (err) { console.error('第一步请求失败:', err); this.$message.error('基础数据加载失败'); return; // 终止后续请求 } let data2 = null; try { data2 = (await this.$axios.get(`/api/endpoint2/${data1.id}`)).data; } catch (err) { console.error('第二步请求失败:', err); this.$message.error('关联数据加载失败'); return; } // 第三步请求同理... }
2. 并行独立请求的异常处理
场景1:只要有一个失败就触发全局错误
export default { data() { return { parallelResults: {} }; }, methods: { async fetchParallelData() { try { // 同时发起三个独立请求 const [resA, resB, resC] = await Promise.all([ this.$axios.get('/api/endpointA'), this.$axios.get('/api/endpointB'), this.$axios.get('/api/endpointC') ]); this.parallelResults = { dataA: resA.data, dataB: resB.data, dataC: resC.data }; } catch (error) { console.error('并行请求出错:', error); this.$message.warning('部分辅助数据加载失败'); } } } };
场景2:容错处理(某个请求失败不影响其他)
如果希望即使某个请求失败,其他请求的结果依然能保留,可以给每个请求单独加catch,返回默认值或错误标记:
async fetchParallelDataWithFallback() { // 给每个请求单独捕获异常,返回带结果/错误的对象 const requests = [ this.$axios.get('/api/endpointA').catch(err => ({ data: null, error: err })), this.$axios.get('/api/endpointB').catch(err => ({ data: null, error: err })), this.$axios.get('/api/endpointC').catch(err => ({ data: null, error: err })) ]; const results = await Promise.all(requests); // 提取有效数据 this.parallelResults = results.map(item => item.data); // 收集错误做后续处理 const errors = results.filter(item => item.error).map(item => item.error); if (errors.length > 0) { console.error('部分并行请求失败:', errors); this.$message.warning('部分辅助数据加载失败'); } }
3. 整体流程:同时发起串行和并行任务
因为后三个请求和前三个无关,你可以同时启动两个任务,提升页面加载效率:
async fetchAllData() { // 并行执行串行任务和并行任务 await Promise.all([ this.fetchSequentialData(), this.fetchParallelDataWithFallback() ]); console.log('所有请求处理完成'); }
四、Vue项目里的额外注意点
- 请求取消,避免内存泄漏
组件销毁时要取消未完成的请求,防止内存泄漏,用Axios的CancelToken实现:
export default { data() { return { cancelToken: null }; }, beforeDestroy() { // 组件销毁时取消所有未完成的请求 if (this.cancelToken) { this.cancelToken.cancel('组件销毁,取消请求'); } }, methods: { async fetchSequentialData() { this.cancelToken = this.$axios.CancelToken.source(); try { const res1 = await this.$axios.get('/api/endpoint1', { cancelToken: this.cancelToken.token }); // 后续请求也要带上cancelToken... } catch (error) { // 判断是否是主动取消的请求 if (this.$axios.isCancel(error)) { console.log('请求已取消:', error.message); } else { // 处理其他错误 } } } } };
- Axios全局错误拦截
把通用错误(比如401、500)放在Axios拦截器里统一处理,减少组件里的重复代码:
// src/utils/axios.js import axios from 'axios'; import { Message } from 'element-ui'; import router from '@/router'; const instance = axios.create({ baseURL: '/api' }); // 响应拦截器:统一处理错误 instance.interceptors.response.use( response => response, error => { if (error.response?.status === 401) { Message.error('登录已过期,请重新登录'); router.push('/login'); } else if (error.response?.status === 500) { Message.error('服务器出错,请稍后重试'); } return Promise.reject(error); } ); export default instance;
然后在Vue里挂载这个Axios实例:
// src/main.js import axios from '@/utils/axios'; Vue.prototype.$axios = axios;
内容的提问来源于stack exchange,提问作者TomJ
相关产品推荐
相关产品推荐

