Vue3并发请求Promise.allSettled的结果处理优化示例
原来的代码// 发送网络请求获取数据 const fetchData async (id: number, workflowInstanceId: number, activityId: number) { const currentId requestId; loading.value true; try { // 并发请求 const [detailResult, fieldResult, auditResult] await Promise.allSettled([ // 获取资金分配明细列表 capitalAllocateApi.getAllocateDetail(id), // 获取活动可编辑字段 getActivityEditableFieldList(activityId), // 获取审批信息列表 getAuditInfoList(workflowInstanceId) ]); // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; // 更新数据 if (detailResult.status fulfilled detailResult.value?.data) { allocateDatas.value detailResult.value.data; } // 等待 watch 回调执行此时 dataLoaded 仍为 false不会错误修改 isModified await nextTick(); dataLoaded.value true; // 标记数据加载完成 isModified.value false; // 重置修改状态未修改 if (fieldResult.status fulfilled fieldResult.value?.data) { editableFieldDatas.value fieldResult.value.data; } if (auditResult.status fulfilled auditResult.value?.data) { auditDatas.value auditResult.value.data; } // 处理错误并友好提示 const hasDetailError detailResult.status ! fulfilled || !detailResult.value?.data; const hasFieldError fieldResult.status ! fulfilled || !fieldResult.value?.data; const hasAuditError auditResult.status ! fulfilled || !auditResult.value?.data; if (hasDetailError hasAuditError) { ElMessage.error(数据加载失败请稍后重试); } else { if (hasDetailError) ElMessage.error(资金分配明细加载失败); if (hasFieldError) ElMessage.error(可编辑字段加载失败); if (hasAuditError) ElMessage.error(审核信息加载失败); } // 渐进式加载核心数据先展示次要数据后加载获取办理选项 const activityInstance props.capitalAllocate?.activityInstance; if (activityInstance) { // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; getAuditOption(activityInstance) .then((result) { // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; auditOption.value result.data; }) .catch((error) { // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; console.error(获取办理选项失败:, error); }); } } catch (error) { console.error(请求过程发生意外错误, error); ElMessage.error(系统错误请稍后重试); } finally { if (isMounted currentId requestId) loading.value false; } };错误处理代码冗余fetchData 中逐个判断并提示可读性较差。 代码臃肿维护成本高。 可封装一个统一处理函数或使用 try-catch 结合错误状态码区分。 这里应该如何修改针对fetchData中错误处理代码冗余的问题可以通过封装统一处理函数或结构化请求配置来优化。以下是两种可行的改进方案重点保持原有业务逻辑核心数据明细审批都失败时显示整体失败其他情况分别提示。方案一封装通用处理函数将请求结果的处理逻辑抽象为一个函数接收请求结果、对应的数据 ref、错误消息和是否为“核心数据”标识。通过遍历请求配置数组统一处理。代码示例typescriptconst fetchData async (id: number, workflowInstanceId: number, activityId: number) { const currentId requestId; loading.value true; try { // 定义请求配置列表 const requests [ { promise: capitalAllocateApi.getAllocateDetail(id), ref: allocateDatas, errorMsg: 资金分配明细加载失败, isCore: true, // 核心数据 }, { promise: getActivityEditableFieldList(activityId), ref: editableFieldDatas, errorMsg: 可编辑字段加载失败, isCore: false, }, { promise: getAuditInfoList(workflowInstanceId), ref: auditDatas, errorMsg: 审核信息加载失败, isCore: true, }, ]; // 并发执行所有请求 const results await Promise.allSettled(requests.map(r r.promise)); // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; // 统计核心数据成功/失败数量 let coreSuccessCount 0; let coreFailCount 0; const errors: string[] []; // 遍历结果依次处理 results.forEach((result, index) { const config requests[index]; if (result.status fulfilled result.value?.data) { // 成功且有数据 config.ref.value result.value.data; if (config.isCore) coreSuccessCount; } else { // 失败或无数据 if (config.isCore) coreFailCount; errors.push(config.errorMsg); } }); // 等待可能的 watch 回调执行 await nextTick(); dataLoaded.value true; isModified.value false; // 核心数据全部失败提示整体错误否则分别提示 if (coreSuccessCount 0 coreFailCount 0) { ElMessage.error(数据加载失败请稍后重试); } else { errors.forEach(msg ElMessage.error(msg)); } // 获取办理选项渐进加载 const activityInstance props.capitalAllocate?.activityInstance; if (activityInstance) { if (!isMounted || currentId ! requestId) return; getAuditOption(activityInstance) .then((result) { if (!isMounted || currentId ! requestId) return; auditOption.value result.data; }) .catch((error) { if (!isMounted || currentId ! requestId) return; console.error(获取办理选项失败:, error); }); } } catch (error) { console.error(请求过程发生意外错误, error); ElMessage.error(系统错误请稍后重试); } finally { if (isMounted currentId requestId) loading.value false; } };优点逻辑集中错误处理与请求配置解耦维护时只需修改配置数组。可扩展性强新增请求只需在requests中添加一项。清晰统计核心数据状态统一判断是否需要显示“整体失败”。方案二使用辅助函数处理单个请求结果定义一个小函数handleRequestResult专门处理单个 Promise 的结果并返回是否成功。然后在主函数中调用。代码示例typescriptconst fetchData async (id: number, workflowInstanceId: number, activityId: number) { const currentId requestId; loading.value true; try { // 并发请求 const [detailResult, fieldResult, auditResult] await Promise.allSettled([ capitalAllocateApi.getAllocateDetail(id), getActivityEditableFieldList(activityId), getAuditInfoList(workflowInstanceId) ]); if (!isMounted || currentId ! requestId) return; // 辅助函数处理单个结果返回是否成功fulfilled且有数据 const handleResult (result: PromiseSettledResultany, ref: any, errorMsg: string): boolean { if (result.status fulfilled result.value?.data) { ref.value result.value.data; return true; } else { return false; } }; // 处理核心数据 const detailOk handleResult(detailResult, allocateDatas, 资金分配明细加载失败); const auditOk handleResult(auditResult, auditDatas, 审核信息加载失败); // 处理非核心数据 handleResult(fieldResult, editableFieldDatas, 可编辑字段加载失败); await nextTick(); dataLoaded.value true; isModified.value false; // 核心数据判断 if (!detailOk !auditOk) { ElMessage.error(数据加载失败请稍后重试); } else { if (!detailOk) ElMessage.error(资金分配明细加载失败); if (!auditOk) ElMessage.error(审核信息加载失败); } // 获取办理选项同上 // ... } catch (error) { // ... } finally { // ... } };优点代码简洁减少了重复的if判断错误消息直接作为参数传递。保留原有结构仍使用Promise.allSettled和独立变量适合少量请求。推荐方案如果后续可能增加更多请求推荐方案一因为它将请求配置化更易于维护和扩展。如果请求数量固定且较少方案二更简单直接。两种方案都消除了冗余代码提高了可读性。其他注意点无论哪种方案都需要保留nextTick和竞态防护逻辑。渐进式加载的getAuditOption请求独立处理因为它依赖前面的结果且非核心保持原样即可。按照以上方式重构后fetchData将更加清晰错误处理逻辑集中且易于修改。优化后的代码// 发送网络请求获取数据 const fetchData async (id: number, workflowInstanceId: number, activityId: number) { const currentId requestId; loading.value true; try { // 并发请求 const [detailResult, fieldResult, auditResult] await Promise.allSettled([ // 获取资金分配明细列表 capitalAllocateApi.getAllocateDetail(id), // 获取活动可编辑字段 getActivityEditableFieldList(activityId), // 获取审批信息列表 getAuditInfoList(workflowInstanceId) ]); // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; // 辅助函数处理单个结果返回是否成功fulfilled且有数据 const handleResult (result: PromiseSettledResultany, ref: any, errorMsg: string): boolean { if (result.status fulfilled result.value?.data) { ref.value result.value.data; return true; } else { return false; } }; // 处理核心数据 const detailOk handleResult(detailResult, allocateDatas, 资金分配明细加载失败); const auditOk handleResult(auditResult, auditDatas, 审核信息加载失败); // 处理非核心数据 handleResult(fieldResult, editableFieldDatas, 可编辑字段加载失败); // 等待 watch 回调执行此时 dataLoaded 仍为 false不会错误修改 isModified await nextTick(); dataLoaded.value true; isModified.value false; // 核心数据判断 if (!detailOk !auditOk) { ElMessage.error(数据加载失败请稍后重试); } else { if (!detailOk) ElMessage.error(资金分配明细加载失败); if (!auditOk) ElMessage.error(审核信息加载失败); } // 渐进式加载核心数据先展示次要数据后加载获取办理选项 const activityInstance props.capitalAllocate?.activityInstance; if (activityInstance) { // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; getAuditOption(activityInstance) .then((result) { // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; auditOption.value result.data; }) .catch((error) { // 前置检查组件已卸载 或 不是当前最新请求则返回 if (!isMounted || currentId ! requestId) return; console.error(获取办理选项失败:, error); }); } } catch (error) { console.error(请求过程发生意外错误, error); ElMessage.error(系统错误请稍后重试); } finally { if (isMounted currentId requestId) loading.value false; } };
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2409265.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!