news 2026/3/5 4:24:55

前端上载文件时,上载多个文件,但是一个一个调用接口,怎么实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端上载文件时,上载多个文件,但是一个一个调用接口,怎么实现

在前端实现多个文件逐个上传,可以通过以下几种方式实现:

1. 使用 async/await 顺序上传

async function uploadFilesSequentially(files) { for (let i = 0; i < files.length; i++) { try { const formData = new FormData(); formData.append('file', files[i]); formData.append('filename', files[i].name); const response = await fetch('/api/upload', { method: 'POST', body: formData }); const result = await response.json(); console.log(`文件 ${files[i].name} 上传成功`, result); // 可以在这里更新上传进度 updateProgress(i + 1, files.length); } catch (error) { console.error(`文件 ${files[i].name} 上传失败:`, error); // 可以选择继续上传剩余文件,或停止上传 // break; // 如果上传失败就停止 } } console.log('所有文件上传完成'); }

2. 使用递归实现顺序上传

function uploadFilesRecursively(files, index = 0) { if (index >= files.length) { console.log('所有文件上传完成'); return Promise.resolve(); } const file = files[index]; const formData = new FormData(); formData.append('file', file); return fetch('/api/upload', { method: 'POST', body: formData }) .then(response => response.json()) .then(result => { console.log(`文件 ${file.name} 上传成功`); updateProgress(index + 1, files.length); // 继续上传下一个文件 return uploadFilesRecursively(files, index + 1); }) .catch(error => { console.error(`文件 ${file.name} 上传失败:`, error); // 可以选择继续上传或停止 return uploadFilesRecursively(files, index + 1); }); }

3. 完整的组件示例

<template> <div> <input type="file" multiple @change="handleFileChange" /> <button @click="uploadFiles">上传文件</button> <!-- 进度显示 --> <div v-if="uploading"> <div>上传进度: {{ uploadedCount }} / {{ totalFiles }}</div> <div>当前文件: {{ currentFileName }}</div> <progress :value="uploadedCount" :max="totalFiles" ></progress> </div> </div> </template> <script setup> import { ref } from 'vue'; import axios from 'axios'; const files = ref([]); const uploading = ref(false); const uploadedCount = ref(0); const totalFiles = ref(0); const currentFileName = ref(''); // 处理文件选择 const handleFileChange = (event) => { files.value = Array.from(event.target.files); }; // 顺序上传文件 const uploadFiles = async () => { if (!files.value.length) return; uploading.value = true; uploadedCount.value = 0; totalFiles.value = files.value.length; for (let i = 0; i < files.value.length; i++) { const file = files.value[i]; currentFileName.value = file.name; try { await uploadSingleFile(file); uploadedCount.value++; } catch (error) { console.error(`文件 ${file.name} 上传失败:`, error); // 可以在这里处理错误,比如记录失败的文件 } } uploading.value = false; console.log('所有文件上传完成'); }; // 上传单个文件 const uploadSingleFile = async (file) => { const formData = new FormData(); formData.append('file', file); formData.append('timestamp', Date.now()); // 可以添加其他参数 formData.append('userId', '123'); formData.append('category', 'documents'); const response = await axios.post('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, // 显示上传进度(可选) onUploadProgress: (progressEvent) => { const percent = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); console.log(`文件 ${file.name} 上传进度: ${percent}%`); } }); return response.data; }; </script>

4. 使用 Promise.reduce 实现顺序执行

import axios from 'axios'; async function sequentialUpload(files) { const results = await files.reduce(async (previousPromise, file, index) => { const previousResults = await previousPromise; console.log(`开始上传第 ${index + 1} 个文件: ${file.name}`); try { const formData = new FormData(); formData.append('file', file); const response = await axios.post('/api/upload', formData); previousResults.push({ file: file.name, success: true, data: response.data }); } catch (error) { previousResults.push({ file: file.name, success: false, error: error.message }); } return previousResults; }, Promise.resolve([])); return results; }

5. 并发控制(推荐)

如果需要兼顾效率和顺序,可以使用并发控制:

class FileUploader { constructor(maxConcurrent = 1) { this.maxConcurrent = maxConcurrent; // 最大并发数 this.queue = []; this.activeCount = 0; this.results = []; } addFile(file) { this.queue.push(file); } async uploadAll() { const batches = []; // 将文件分批 for (let i = 0; i < this.queue.length; i += this.maxConcurrent) { batches.push(this.queue.slice(i, i + this.maxConcurrent)); } // 按批次顺序执行 for (const batch of batches) { const batchPromises = batch.map(file => this.uploadSingle(file)); const batchResults = await Promise.allSettled(batchPromises); this.results.push(...batchResults); } return this.results; } async uploadSingle(file) { const formData = new FormData(); formData.append('file', file); return axios.post('/api/upload', formData); } } // 使用示例 const uploader = new FileUploader(3); // 最多3个并发 files.forEach(file => uploader.addFile(file)); uploader.uploadAll().then(results => { console.log('上传结果:', results); });

关键注意事项:

  1. 错误处理:每个文件上传都应该有独立的错误处理

  2. 进度反馈:给用户显示上传进度

  3. 取消上传:提供取消上传的功能

  4. 重试机制:对失败的上传提供重试功能

  5. 性能优化:大文件可以考虑分片上传

  6. 内存管理:及时释放不再需要的文件对象

选择哪种方案取决于你的具体需求:

  • 如果需要严格的顺序执行,使用方案1或2

  • 如果需要更好的性能,可以使用方案5的并发控制

  • 如果需要在Vue/React中使用,可以结合框架的特性

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/3 10:01:22

DeepSeek vs 豆包降AI效果大比拼:同一篇论文测下来差距惊人

DeepSeek vs 豆包降AI效果大比拼&#xff1a;同一篇论文测下来差距惊人 TL;DR 用同一篇论文实测DeepSeek和豆包的降AI效果&#xff0c;结论是&#xff1a;它们本质上还是AI在生成内容&#xff0c;降完后AIGC检测仍然难以通过。真正靠谱的方案是用专业降AI工具&#xff0c;比如…

作者头像 李华
网站建设 2026/3/1 7:23:15

深度学习毕设项目:基于深度学习对马路道路是否破损识别基于python-CNN深度学习对马路道路是否破损识别

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/2/27 10:03:00

Zynq上UART/IIC/SPI的27个实验-第1课:PS 硬件 UART 发送

目录 目标 每隔1s发出一条消息 BD main.cpp #include "xparameters.h" #include "xuartps.h" #include "xil_printf.h" #include "sleep.h" #include <string.h>/* 配置 */#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_…

作者头像 李华