Skip to content

ProgressWithRequest 组件

面试官:你在项目里封装过什么异步进度类的组件吗?

是的,在我们 DMP 项目里我封装过一个 ProgressWithRequest 组件。它的定位是把“发起操作请求”和“进度展示”整合在一起,避免业务页重复写轮询和状态管理。

面试官:大概怎么实现的?

这个组件是个容器组件,内部用的展示组件是 Progress。挂载时如果有 progressId 会直接开始追踪;如果没有,就先调用外部传进来的 promise 发起操作,拿到 progress_id 后开始轮询。轮询周期是 1 秒,拿到的进度数据里会包含 step_indexstepsdone_messageerror 等字段。我在 setState 的回调里判断:有 done_message 视为成功,触发成功提示和回调;有 error 就停轮询并显示错误;否则继续下一轮。组件还支持在成功时延迟 1 秒关闭弹窗,并暴露了 successafterSuccessmodalHideonWarningNotificationClick 等钩子,方便业务做收尾或打开告警详情。

面试官:现在是轮询,如果想优化成 SSE 或 WebSocket,可以怎么做?

可以的。SSE 适合单向推送,接入成本低,浏览器原生 EventSource,只要后端提供 text/event-stream 就能用;WebSocket 适合需要双向指令,比如用户想主动取消操作或查询更多细节。接入上我会保留轮询作兜底,优先尝试 SSE/WebSocket,失败再回退轮询。前端改造要点是:挂载时建立连接,收到进度消息就直接 setState 更新 step;收到完成或错误就关闭连接并走现有的成功/失败分支;在卸载或手动取消时要清理连接。WebSocket 额外需要心跳和重连策略。后端需要按当前的进度数据结构推送,并提供完成/失败标志,最好还能支持鉴权和取消的语义。

面试官:如果再迭代,你会做什么优化?

我会考虑用 Hooks 重写,减少类生命周期的复杂度;把轮询/推送逻辑抽成自定义 Hook,便于复用和测试;补充定时器与连接的清理;增加轮询间隔可配置,增强错误处理;最后补上单元测试覆盖成功、失败、网络异常和卸载场景。