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

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

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中使用,可以结合框架的特性

相关推荐
NCDS程序员8 小时前
v-model: /v-model/ :(v-bind)三者核心区别
前端·javascript·vue.js
夏幻灵8 小时前
CSS三大特性:层叠、继承与优先级解析
前端·css
小杨同学呀呀呀呀8 小时前
Ant Design Vue <a-timeline>时间轴组件失效解决方案
前端·javascript·vue.js·typescript·anti-design-vue
华玥作者16 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_17 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠17 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang2015092817 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC18 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务18 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整19 小时前
面试点(网络层面)
前端·网络