乐闻世界logo
搜索文章和话题

axios 中如何实现并发请求和取消请求?请提供代码示例

3月7日 12:10

Axios 并发请求

Axios 提供了 axios.all()axios.spread() 方法来处理并发请求,同时也支持使用原生的 Promise.all()

1. 使用 Promise.all()(推荐)

javascript
// 同时发送多个请求 async function fetchMultipleData() { try { const [users, posts, comments] = await Promise.all([ axios.get('/api/users'), axios.get('/api/posts'), axios.get('/api/comments') ]); console.log('Users:', users.data); console.log('Posts:', posts.data); console.log('Comments:', comments.data); return { users: users.data, posts: posts.data, comments: comments.data }; } catch (error) { console.error('至少一个请求失败:', error); throw error; } }

2. 使用 axios.all()(传统方式)

javascript
axios.all([ axios.get('/api/users'), axios.get('/api/posts'), axios.get('/api/comments') ]) .then(axios.spread((users, posts, comments) => { // 所有请求都成功时执行 console.log('Users:', users.data); console.log('Posts:', posts.data); console.log('Comments:', comments.data); })) .catch(error => { // 任一请求失败时执行 console.error('请求失败:', error); });

3. 并发请求的错误处理

javascript
async function fetchWithErrorHandling() { const requests = [ axios.get('/api/users'), axios.get('/api/posts'), axios.get('/api/comments') // 可能失败的请求 ]; // 使用 Promise.allSettled 等待所有请求完成 const results = await Promise.allSettled(requests); results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`请求 ${index} 成功:`, result.value.data); } else { console.error(`请求 ${index} 失败:`, result.reason.message); } }); // 过滤出成功的结果 const successfulResults = results .filter(result => result.status === 'fulfilled') .map(result => result.value.data); return successfulResults; }

4. 限制并发数量

javascript
// 使用 p-limit 或自定义实现限制并发 async function fetchWithConcurrencyLimit(urls, limit = 3) { const results = []; const executing = []; for (const [index, url] of urls.entries()) { const promise = axios.get(url).then(res => ({ index, data: res.data })); results.push(promise); if (urls.length >= limit) { executing.push(promise); if (executing.length >= limit) { await Promise.race(executing); executing.splice( executing.findIndex(p => p === promise), 1 ); } } } return Promise.all(results); } // 使用 const urls = ['/api/data/1', '/api/data/2', '/api/data/3', '/api/data/4']; fetchWithConcurrencyLimit(urls, 2);

Axios 取消请求

1. 使用 AbortController(推荐,v0.22.0+)

javascript
// 创建 AbortController const controller = new AbortController(); // 发送请求时传入 signal axios.get('/api/data', { signal: controller.signal }) .then(response => { console.log(response.data); }) .catch(error => { if (axios.isCancel(error)) { console.log('请求已取消:', error.message); } else { console.error('请求失败:', error); } }); // 取消请求 controller.abort('用户取消操作'); // 5秒后自动取消 setTimeout(() => { controller.abort('请求超时'); }, 5000);

2. 在 React 组件中使用

javascript
import { useEffect } from 'react'; function UserList() { useEffect(() => { const controller = new AbortController(); const fetchUsers = async () => { try { const response = await axios.get('/api/users', { signal: controller.signal }); // 处理数据 } catch (error) { if (axios.isCancel(error)) { console.log('组件卸载,请求已取消'); } else { console.error('获取用户失败:', error); } } }; fetchUsers(); // 组件卸载时取消请求 return () => { controller.abort('组件卸载'); }; }, []); return <div>User List</div>; }

3. 在 Vue 组件中使用

javascript
<script setup> import { onMounted, onUnmounted } from 'vue'; let controller; onMounted(() => { controller = new AbortController(); axios.get('/api/data', { signal: controller.signal }) .then(response => { console.log(response.data); }) .catch(error => { if (axios.isCancel(error)) { console.log('请求已取消'); } }); }); onUnmounted(() => { controller?.abort('组件卸载'); }); </script>

4. 取消多个请求

javascript
const controllers = new Map(); // 发送请求时保存 controller function fetchWithCancel(key, url) { // 取消之前的同名请求 if (controllers.has(key)) { controllers.get(key).abort('重复请求,取消前一个'); } const controller = new AbortController(); controllers.set(key, controller); return axios.get(url, { signal: controller.signal }) .finally(() => { controllers.delete(key); }); } // 使用:搜索框防抖场景 fetchWithCancel('search', '/api/search?q=keyword');

5. 请求超时自动取消

javascript
async function fetchWithTimeout(url, timeout = 5000) { const controller = new AbortController(); const timeoutId = setTimeout(() => { controller.abort(`请求超时 (${timeout}ms)`); }, timeout); try { const response = await axios.get(url, { signal: controller.signal }); clearTimeout(timeoutId); return response.data; } catch (error) { clearTimeout(timeoutId); throw error; } }

6. 取消请求的工具函数封装

javascript
class RequestManager { constructor() { this.controllers = new Map(); } // 发送请求 async request(key, config) { // 取消之前的同名请求 this.cancel(key); const controller = new AbortController(); this.controllers.set(key, controller); try { const response = await axios({ ...config, signal: controller.signal }); return response; } finally { this.controllers.delete(key); } } // 取消指定请求 cancel(key, message = '请求被取消') { if (this.controllers.has(key)) { this.controllers.get(key).abort(message); this.controllers.delete(key); } } // 取消所有请求 cancelAll(message = '所有请求被取消') { this.controllers.forEach(controller => { controller.abort(message); }); this.controllers.clear(); } } // 使用 const requestManager = new RequestManager(); // 发送请求 requestManager.request('userList', { method: 'GET', url: '/api/users' }); // 取消指定请求 requestManager.cancel('userList'); // 取消所有请求(如页面切换时) requestManager.cancelAll();

最佳实践

  1. 组件卸载时取消请求:避免内存泄漏和状态更新错误
  2. 重复请求时取消前一个:搜索框、表单提交等场景
  3. 设置合理的超时时间:防止请求挂起
  4. 正确处理取消错误:区分取消错误和业务错误
  5. 使用 AbortController:现代浏览器标准 API,兼容性好
标签:JavaScript前端Axios