并行发起http请求
1. 使用 axios + Promise.all
<template><input type="file" multiple @change="handleFileUpload" />
</template><script>
import axios from 'axios';export default {methods: {async handleFileUpload(event) {const files = event.target.files;if (!files.length) return;try {// 并行上传所有文件const uploadPromises = Array.from(files).map(file => {const formData = new FormData();formData.append('file', file); // 后端接收的字段名可能是 'file'return axios.post('/api/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' },});});// 等待所有请求完成const results = await Promise.all(uploadPromises);console.log('所有文件上传成功:', results.map(res => res.data));} catch (error) {console.error('上传失败:', error);}},},
};
</script>
FormData 用于构造文件上传请求。
Promise.all 并行发起多个上传请求。
headers: { ‘Content-Type’: ‘multipart/form-data’ } 必须设置,否则后端可能无法正确解析文件。
2. 使用 fetch + async/await
如果不依赖 axios,可以使用原生 fetch 实现
async function uploadFiles(files) {try {const uploadPromises = Array.from(files).map(file => {const formData = new FormData();formData.append('file', file);return fetch('/api/upload', {method: 'POST',body: formData,// fetch 默认会自动设置 multipart/form-data});});const responses = await Promise.all(uploadPromises);const results = await Promise.all(responses.map(res => res.json()));console.log('上传结果:', results);} catch (error) {console.error('上传失败:', error);}
}
3. 限制并发上传数量(避免服务器压力过大)
如果同时上传大量文件(如 100+),可以使用 p-limit 控制并发数。
import pLimit from 'p-limit';const limit = pLimit(3); // 最多同时上传3个文件async function uploadWithLimit(files) {try {const uploadPromises = files.map(file => limit(() => {const formData = new FormData();formData.append('file', file);return axios.post('/api/upload', formData);}));const results = await Promise.all(uploadPromises);console.log('上传成功:', results);} catch (error) {console.error('上传失败:', error);}
}
大文件批量上传(如云盘应用)。
避免浏览器或服务器因并发过高而崩溃
4. 显示上传进度
如果需要显示每个文件的上传进度,可以使用 axios 的 onUploadProgress
const uploadPromises = files.map(file => {const formData = new FormData();formData.append('file', file);return axios.post('/api/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' },onUploadProgress: progressEvent => {const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100);console.log(`${file.name} 上传进度: ${percent}%`);// 可以更新 Vue 的 data 或 store 来显示进度条},});
});await Promise.all(uploadPromises);
取消请求:
如果用户离开页面,可以使用 axios.CancelToken 或 AbortController 取消未完成的请求,避免内存泄漏。
如果希望即使某些文件上传失败,也能继续处理成功的文件,可以使用 Promise.allSettled
<template><div><input type="file" multiple @change="handleFileUpload" /><div v-if="uploading">上传中... {{ progress }}%</div><div v-for="(result, index) in results" :key="index">文件 {{ index + 1 }}: {{ result.status === 'success' ? '成功' : '失败' }}</div></div>
</template><script>
import axios from 'axios';export default {data() {return {uploading: false,progress: 0,results: [],};},methods: {async handleFileUpload(event) {const files = event.target.files;if (!files.length) return;this.uploading = true;this.results = [];try {const uploadPromises = Array.from(files).map(file => {const formData = new FormData();formData.append('file', file);return axios.post('/api/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' },onUploadProgress: progressEvent => {this.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);},});});const settledResults = await Promise.allSettled(uploadPromises);this.results = settledResults.map(result => ({status: result.status === 'fulfilled' ? 'success' : 'error',data: result.status === 'fulfilled' ? result.value.data : result.reason,}));} catch (error) {console.error('上传出错:', error);} finally {this.uploading = false;}},},
};
</script>