如何为带固定请求间隔的fetch轮询添加超时终止逻辑
解决方案
实现思路
通过标记位或者时间差判断是否达到15秒超时阈值,满足条件时直接终止递归调用即可,不需要改动原有异步逻辑结构。
下面提供两种实现方式:
方案1:时间差判断(实现简单,无需额外定时器)
每次进入重试分支时计算当前时间与轮询初始时间的差值,超过15s则直接触发弹窗终止递归。
完整代码:
const addDelay = timeout => new Promise(resolve => setTimeout(resolve, timeout)) export const myReport = () => async (dispatch) => { dispatch({ type: constants.DOWNLOAD_REPORT_REQUEST }) let url = `/admin/dashboard/report.js?project_id=${projectId}&tool_id=${toolId}` try { // 新增:记录轮询开始时间 const pollStartTime = Date.now() const subscribe = async (uri) => { let response = await fetch(uri, { method: 'GET', headers: { 'content-type': 'application/json', 'x-api-token': `Bearer ${token}` } }) const resBody = await response.json() if (resBody.status === 'success') { window.location.href = resBody.url dispatch({ type: constants.DOWNLOAD_REPORT_SUCCESS }) } else { // 新增:判断是否超时 const elapsed = Date.now() - pollStartTime if (elapsed >= 15000) { dispatch({ type: constants.SHOW_DOWNLOAD_POPUP }) return } await addDelay(5000) await subscribe(url) } } subscribe(url) } catch (error) { dispatch({ type: constants.DOWNLOAD_REPORT_FAILURE, errorMessage: error.status }) } }
方案2:超时标记位(超时判定更精准,到15秒立刻终止)
提前设置15秒定时器修改终止标记位,每次进入重试分支前优先判断标记位状态。
完整代码:
const addDelay = timeout => new Promise(resolve => setTimeout(resolve, timeout)) export const myReport = () => async (dispatch) => { dispatch({ type: constants.DOWNLOAD_REPORT_REQUEST }) let url = `/admin/dashboard/report.js?project_id=${projectId}&tool_id=${toolId}` try { // 新增:超时标记与超时定时器 let isPollTimeout = false const timeoutTimer = setTimeout(() => { isPollTimeout = true }, 15000) const subscribe = async (uri) => { let response = await fetch(uri, { method: 'GET', headers: { 'content-type': 'application/json', 'x-api-token': `Bearer ${token}` } }) const resBody = await response.json() if (resBody.status === 'success') { // 成功后清除定时器,避免内存泄漏 clearTimeout(timeoutTimer) window.location.href = resBody.url dispatch({ type: constants.DOWNLOAD_REPORT_SUCCESS }) } else { // 优先判断是否已经超时 if (isPollTimeout) { dispatch({ type: constants.SHOW_DOWNLOAD_POPUP }) return } await addDelay(5000) await subscribe(url) } } subscribe(url) } catch (error) { dispatch({ type: constants.DOWNLOAD_REPORT_FAILURE, errorMessage: error.status }) } }
内容的提问来源于stack exchange,提问作者sg055322
相关产品推荐
相关产品推荐

