axios的两种异步方式对比
这两种方式本质上都是异步的,都是基于 Promise 的机制,但它们在语法风格、可读性、错误处理、控制流方面有一些关键区别。下面我来帮你全面对比:
语法结构对比
方式 | 写法 | 特点 |
---|---|---|
.then().catch() | axios.get(...).then(...).catch(...) | 链式调用,适合简单逻辑 |
async/await | await axios.get(...) | 更接近同步语法,适合复杂流程 |
示例对比
方式一:.then().catch()
(链式调用)
axios.get('/api/data').then(res => {console.log(res.data);}).catch(err => {console.error(err);});
优点:语法简洁,适合快速调用。
缺点:嵌套多层
.then()
时容易变得混乱(回调地狱)。
方式二:async/await
(同步风格)
async function fetchData() {try {const res = await axios.get('/api/data');console.log(res.data);} catch (err) {console.error(err);}
}
优点:逻辑清晰,异常处理统一,适合复杂流程。
缺点:必须在
async
函数中使用,略微多一层结构。
错误处理对比
场景 | .then().catch() | async/await |
---|---|---|
单个请求失败 | .catch() 捕获 | try/catch 捕获 |
多个请求嵌套 | 多个 .catch() | 一个 try/catch 统一处理 |
异步函数中抛错 | 不易追踪 | 更易定位错误位置 |
控制流对比(多个请求)
.then()
写法:
axios.get('/api/user').then(user => {return axios.get(`/api/posts?user=${user.id}`);}).then(posts => {console.log(posts.data);}).catch(err => console.error(err));
async/await
写法:
async function getUserPosts() {try {const user = await axios.get('/api/user');const posts = await axios.get(`/api/posts?user=${user.data.id}`);console.log(posts.data);} catch (err) {console.error(err);}
}
async/await
更像同步代码,逻辑更清晰,调试更容易。
总结建议
使用场景 | 推荐方式 |
---|---|
简单请求 | .then().catch() |
多步异步流程 | async/await |
错误处理统一 | async/await |
可读性优先 | async/await |
快速测试或临时调用 | .then() |
如果你正在开发 Vue 项目中的 API 模块,我建议你封装所有请求为 async
函数,这样在组件中调用时更清晰、更易维护。
企业级 API 请求模块示例
基于 axios
,支持以下功能:
✅ 自动注入 Token(如 JWT)
✅ 全局错误处理(如 401、500)
✅ 请求/响应拦截器
✅ Loading 状态支持
✅ 自动重试机制(可选)
✅ 支持异步
async/await
调用
项目结构建议
src/
├── api/
│ ├── axios.js # axios 实例配置
│ ├── request.js # 封装请求方法
│ └── modules/
│ └── user.js # 用户相关接口
1.axios.js — 创建 axios 实例
// src/api/axios.js
import axios from 'axios';const instance = axios.create({baseURL: '/api', // 可根据环境配置timeout: 10000,headers: {'Content-Type': 'application/json'}
});// 请求拦截器
instance.interceptors.request.use(config => {const token = localStorage.getItem('access_token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
}, error => Promise.reject(error));// 响应拦截器
instance.interceptors.response.use(response => {return response.data;
}, error => {const { response } = error;if (response) {if (response.status === 401) {console.warn('未授权,请重新登录');// 可跳转登录页或清除 token} else if (response.status >= 500) {console.error('服务器错误');}} else {console.error('网络异常');}return Promise.reject(error);
});export default instance;
2.request.js — 封装请求方法
// src/api/request.js
import axios from './axios';export const get = (url, params = {}) => {return axios.get(url, { params });
};export const post = (url, data = {}) => {return axios.post(url, data);
};export const put = (url, data = {}) => {return axios.put(url, data);
};export const del = (url, params = {}) => {return axios.delete(url, { params });
};
3. modules/user.js — 用户接口模块
// src/api/modules/user.js
import { get, post } from '../request';export const login = data => post('/login', data);
export const getUserInfo = () => get('/user/info');
export const logout = () => post('/logout');
4. Vue 中调用示例
import { login, getUserInfo } from '@/api/modules/user';async function handleLogin(formData) {try {const res = await login(formData);localStorage.setItem('access_token', res.access_token);console.log('登录成功:', res.user);} catch (err) {console.error('登录失败:', err);}
}
可选增强功能
功能 | 实现方式 |
---|---|
自动刷新 Token | 拦截器中检测 401,调用 refresh 接口 |
Loading 状态 | 在请求前后触发全局 loading(如 Vuex 或 Pinia) |
请求重试 | 使用 axios-retry 插件或自定义逻辑 |
多环境配置 | 使用 .env 文件设置 baseURL |