在使用 Redux-Thunk 异步操作的 Promise 链中使用 setInterval

Posted

技术标签:

【中文标题】在使用 Redux-Thunk 异步操作的 Promise 链中使用 setInterval【英文标题】:Using setInterval in promise chain which uses Redux-Thunk async action 【发布时间】:2020-02-22 06:02:04 【问题描述】:

我有一个相当模糊的问题,它确实可能是我自己的问题,如果是这样,请随时指出。

我有一个承诺链,我需要访问中间值以进行后续 API 调用。一旦所有承诺都得到解决,我就会执行一个 API 调用,该调用利用各种中间返回值。

最后,根据该调用的结果,我对 API 进行最终调用。但是,此调用的结果用于更新 Redux 状态,因此使用 Redux Thunk 作为中间件来促进异步操作。

挑战出现在我需要以设定的时间间隔轮询数据库以检查 Redux API 调用是否执行了它所请求的工作(这涉及在 Redis 任务队列中放置一些长时间运行的任务,然后任务完成后让队列工作人员更新数据库)。

当数据库确认确实已更新完成任务状态时,我想清除setIntervalId。我已将代码简化为如下所示。问题是执行不会等待 Redux 异步操作完成。因此,它执行该操作,然后在 Redux 操作完成之前直接执行“if”检查。因此 if 永远不会为真,并且轮询会无限期地继续。

我不知道如何确保 Redux Action 在代码继续之前完成。我已经精简了代码以使逻辑到位,而不会用不相关的代码过度拥挤这篇文章。

有什么想法可以让它按预期工作吗?

buttonClickedHandler.js

callbackFn function()
    const a = ApiCallA(...) // Returns a promise

    const b = a.then(resA => 
        // Some work done here
        return ApiCallB(…); // Returns a promise

    const c = b.then(resB => 
        // Some work done here
        return ApiCallC(…); // Returns a promise  

    return Promise.all( ([a, b, c] )
        .then( ([resA, resB, resC] ) => 
            // Some work done here
            return ApiCallD
        )
        .then( resD => 
            const intId = setInterval( () => 
                reduxAsyncAction(resD.jobId) // <-- This makes a final API call
                    if (props.jobStatus) // <-- jobStatus gets updated too late
                         clearInterval(intId ); 
                    
                , 5000)
          )
         .catch(err => console.log(err))


redux action creator

export const reduxAsyncAction= (jobId) => 
    return dispatch => 
        dispatch(taskStatusStart()); // <- Basic sync. action creator
        return databaseQuery() // Returns Promise therefore pushed to taskqueue while other function run
        .then(dbData=>
            const completionStatus = dbData.status; // <- True or False
            dispatch(taskStatusSuccess(completionStatus)) // <- Basic sync. action creator
        ,
        error => 
            dispatch(taskStatusFail(error)); // <- Basic sync. action creator
        )
    ;



【问题讨论】:

我不知道 reactjs/redux 的来龙去脉——我所知道的是你的 reduxAsyncAction 函数返回一个 Promise,你基本上不会在那个 setInterval 回调中忽略它 【参考方案1】:

使用componentDidUpdateuseEffect

    只要 props.jobStatus 在您的 redux 存储中更新,这些就会运行 检查您从reduxAsyncAction 发送的taskStatusSuccess(completionStatus)taskStatusFail(error) clearinterval(intId) 如果状态匹配

您还需要通过在callbackFn 之外声明,将intId 添加到范围内,例如:

this.intId 在基于类的组件的构造函数中

let intId 在功能组件的顶部。

基于类的组件:

componentDidUpdate()
    if (intId && props.jobStatus === 'completionStatus' || props.jobStatus === 'error')
          clearInterval(intId); 
          intId = null;
     

功能组件:

useEffect(()=>
    if (intId && props.jobStatus === 'completionStatus' || props.jobStatus === 'error')
        clearInterval(intId); 
        intId = null;
     
,[props.jobStatus])

【讨论】:

你好威廉。感谢您的回复。不幸的是,这仍然给我留下了异步 redux thunk 调用在执行 if 语句之前没有完全完成的问题。 我更新了我的答案,我相信会更清楚。让我知道我是否仍然错过了标记,干杯!

以上是关于在使用 Redux-Thunk 异步操作的 Promise 链中使用 setInterval的主要内容,如果未能解决你的问题,请参考以下文章

redux-thunk:错误:动作必须是普通对象。使用自定义中间件进行异步操作

使用 redux-thunk 进行异步验证

在 redux-thunk 中调用另一个异步函数

安装了 redux-thunk 的 redux 操作中的异步函数错误

Redux-thunk 异步调用和状态

使用 axios 的 redux-thunk 的通用数据加载器