这两种方式本质上都是异步的,都是基于 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 |