Vue Pinia中不使用await,基于响应式实现API顺序调用方案咨询
Vue响应式优化文件上传与POST请求实现
我目前在项目里用手动计数和回调处理文件上传,之后再发起最终POST请求,但团队前辈建议用Vue的响应式特性来优化。虽然可以用await,但我对响应式实现方式有点困惑,现有代码如下,求更优方案:
现有实现代码
App.vue
const isLoading = ref(0) function Requester(url, method, data = null, callback = null) { // TODO: Remove primitive request counting technique and use reactive pattern isLoading.value++ axios(url, { method: method, data: data }) .then((response) => { if (callback) callback(response) }) .catch((reason) => { alert(reason) }) .finally(() => { isLoading.value-- }) }
store.js
export const documentLibraryStore = defineStore('documentLibrary', () => { const useDocStore = doctore() const useGeneratedDocStore = generatedDocStore() const document = useGeneratedDocStore.newDocument const files = ref([]) function isUploadDoneForAllFiles(uploadCount, extraFileCount) { return document.files.length - uploadCount == extraFileCount } function uploadPdfs() { let uploadCount = 0 let extraFileCount = 0 document.files.forEach((doc) => { if (!doc.id) { // id is undefind for non uploaded file add(doc.fileData, (value) => { uploadCount++ doc.id = value.id // Here I am checking if files are uploaded or not if (isUploadDoneForAllFiles(uploadCount, extraFileCount)) { publish(document) } }) } else { extraFileCount++ if (extraFileCount == document.files.length) publish(document) } }) } function formatPublishPayload() { document.files = document.files.map((file) => { return { id: file.id, fileId: file.fileId } }) } // This should only called once we have id's for files uploaded function publish(documentset) { formatPublishPayload() if (document) { request('URL_TO_UPLOAD_DOCUMENT', 'POST', documentset, (response) => { useDocStore.appendDocumentSets(response.data) useGeneratedDocStore.clearNewDocumentSet() }) } } function add(uploadFile, setID) { if (uploadFile) { const formData = new FormData() formData.append('file', uploadFile) request('URL_TO_UPLOAD_FILE', 'POST', formData, (value) => { files.value.push(value.data[0]) // this is call back I am using to set id received from backend to set for uploaded files setID(value.data[0]) }) } } function publishDocumentSet() { uploadPdfs() } return { files, add, publishDocumentSet } })
响应式优化方案
1. 重构Requester为异步函数,移除回调依赖
把Requester改成返回Promise的async函数,用await处理异步请求,同时保留loading计数逻辑:
// App.vue const isLoading = ref(0) async function Requester(url, method, data = null) { isLoading.value++ try { const response = await axios(url, { method, data }) return response } catch (reason) { alert(reason) throw reason // 抛出错误方便上层捕获处理 } finally { isLoading.value-- } }
2. 基于响应式状态跟踪文件上传情况
不再手动维护计数变量,利用Vue响应式特性跟踪文件上传状态,用Promise.all批量处理上传请求:
// store.js export const documentLibraryStore = defineStore('documentLibrary', () => { const useDocStore = doctore() const useGeneratedDocStore = generatedDocStore() const document = useGeneratedDocStore.newDocument const files = ref([]) // 新增响应式变量防止重复上传 const isUploading = ref(false) // 计算属性:自动判断所有文件是否已上传(都有id) const allFilesUploaded = computed(() => { return document.files.every(doc => !!doc.id) }) // 监听上传完成状态,自动触发publish watch(allFilesUploaded, (isDone) => { if (isDone && !isUploading.value) { publish(document) } }, { immediate: true }) // 立即执行,处理已有文件全部上传的场景 async function uploadPdfs() { if (isUploading.value) return // 避免重复触发上传 isUploading.value = true // 批量发起未上传文件的请求 const uploadPromises = document.files .filter(doc => !doc.id) .map(async (doc) => { const response = await add(doc.fileData) // 响应式更新文件id,触发计算属性变更 doc.id = response.data[0].id doc.fileId = response.data[0].fileId return response }) try { await Promise.all(uploadPromises) } catch (error) { console.error('文件上传失败:', error) } finally { isUploading.value = false } } function formatPublishPayload() { document.files = document.files.map((file) => { return { id: file.id, fileId: file.fileId } }) } async function publish(documentset) { if (!documentset) return formatPublishPayload() try { const response = await Requester('URL_TO_UPLOAD_DOCUMENT', 'POST', documentset) useDocStore.appendDocumentSets(response.data) useGeneratedDocStore.clearNewDocumentSet() } catch (error) { console.error('发布请求失败:', error) } } async function add(uploadFile) { if (!uploadFile) return const formData = new FormData() formData.append('file', uploadFile) const response = await Requester('URL_TO_UPLOAD_FILE', 'POST', formData) files.value.push(response.data[0]) return response } function publishDocumentSet() { uploadPdfs() } return { files, add, publishDocumentSet, allFilesUploaded, isUploading } })
优化点说明
- 移除回调与手动计数:用
async/await替代回调避免嵌套,通过计算属性allFilesUploaded自动判断上传完成状态,无需手动维护计数变量。 - 响应式自动触发逻辑:通过
watch监听上传完成状态,符合Vue响应式设计思想,无需手动判断执行时机。 - 防重复操作:新增
isUploading变量避免重复发起上传请求,提升交互稳定性。 - 错误处理更清晰:每个异步环节单独捕获错误,便于定位问题,替代全局alert提示更友好。
内容的提问来源于stack exchange,提问作者Nixit Ahir
相关产品推荐
相关产品推荐

