使用reduce方法串行上传附件无法获取返回响应的解决方法
问题排查结果
当前代码拿不到上传返回响应的核心原因有3个:
reduce实现的Promise顺序链没有收集每个上传任务的返回值,初始传入的Promise.resolve()没有带初始累加值,最后链执行完成后自然拿不到所有文件的上传结果- 整个上传链没有加
catch错误捕获,只要中间任意一个文件上传出问题,整个链会静默失败,不会走到你写的console.log(res)逻辑里 - 代码里存在边界漏洞:全局
files数组未初始化、用户选择文件时点取消会因为event.target.files为null抛错、重复选择同一个文件不会触发change事件,这些都会导致上传流程中断无响应。
修复后完整代码
首先补全基础变量初始化:
// 如果你用的是Vue3,补对应响应式API引入即可 const files: File[] = [] const filesUpload = ref<File[]>([]) const uploadPercentage = ref(0) // 用来存储按上传顺序排列的所有文件返回URL const uploadedFileUrls = ref<string[]>([])
修复文件选择方法:
const uploadFile = (event: any, type: Number = 1) => { // 拦截用户点取消选文件的场景,避免空值报错 if (!event.target.files?.length) return const file: File = event.target.files[0] files.push(file) // 用新数组赋值触发响应式更新 filesUpload.value = [...files] // 清空input值,解决重复选同一个文件不触发change的问题 event.target.value = '' }
修复顺序上传逻辑,增加结果收集和错误捕获:
const save = () => { if (!filesUpload.value?.length) return const fileList = filesUpload.value uploadedFileUrls.value = [] // 顺序上传+结果收集 const uploadQueue = (files: File[]) => { return files.reduce((prevTask, currentFile) => { return prevTask.then((collectedUrls) => { // 等当前文件上传完成后,把返回的URL拼到结果数组里传给下一个then return uploadAttachment(currentFile).then(fileUrl => { return [...collectedUrls, fileUrl] }) }) // 初始值传空数组,作为第一个then的入参 }, Promise.resolve([] as string[])) } uploadQueue(fileList) .then((allUrls) => { // 这里拿到的就是和选择顺序一致的所有文件上传返回结果 console.log('全部上传完成,文件地址列表:', allUrls) uploadedFileUrls.value = allUrls // 后续提交表单等逻辑可以写在这里 }) .catch(err => { console.error('上传流程中断:', err) // 错误捕获后可以在这里加用户提示逻辑 }) }
原uploadAttachment方法逻辑本身没有问题,可以直接使用;如果你需要显示整体上传进度,可以在进度回调里调整计算逻辑,单文件进度场景不需要改动:
const uploadAttachment = (attachment: File): Promise<any> => { return new Promise((resolve, reject) => { const storageRef = storage.ref(attachment.name).put(attachment); storageRef.on(`state_changed`, snapshot => { uploadPercentage.value = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 }, error => { reject(error); }, () => { uploadPercentage.value = 100; storageRef.snapshot.ref.getDownloadURL().then(url => { resolve(url); }).catch(err => { reject(err) }) }) }) }
修复点说明
- 给
reduce的Promise链传入空数组作为初始累加值,每上传完一个文件就把返回的URL追加到数组里传递,最终能拿到完整的按顺序排列的上传结果 - 增加了全局catch捕获,上传过程中任意环节出错都会触发错误回调,不会再出现无响应的情况
- 补全了所有边界场景的判断,避免隐式报错中断上传流程
内容的提问来源于stack exchange,提问作者Robin Singh
相关产品推荐
相关产品推荐

