如何避免async异步事件处理函数执行顺序混乱(React+Redux场景)
问题解决方案
方案1:添加操作上下文标识(适配Redux场景,通用性最强)
- 每次触发滑块打开时,生成一个唯一的随机会话ID,同时写入Redux的滑块状态模块和当前点击事件的闭包中
- 拉取数据写入Redux时,校验本次会话ID和Redux中存储的当前会话ID是否一致,仅一致时允许更新数据
- 修改
onSliderClose清理逻辑:清理前先校验当前闭包存储的会话ID和Redux中存储的当前会话ID是否一致,不一致说明已经打开新滑块,直接终止旧的清理逻辑
示例代码:
// 元素点击打开滑块逻辑 const onClickElement = async (itemId) => { const sessionId = Date.now() + Math.random().toString(16).slice(2) dispatch(setSliderSessionId(sessionId)) openSlider() const resData = await fetchSliderDetail(itemId) // 会话ID匹配才写入数据 if (sessionId === getState().slider.currSessionId) { dispatch(setSliderData(resData)) } } // 滑块关闭清理逻辑 const onSliderClose = async () => { // 缓存当前关闭操作对应的会话ID const currSessionId = getState().slider.currSessionId await asyncClearTask1() await asyncClearTask2() // 会话ID匹配才执行数据清空 if (currSessionId === getState().slider.currSessionId) { dispatch(clearSliderAllData()) dispatch(setSliderSessionId(null)) } }
方案2:新增操作状态锁(适合业务逻辑简单的场景)
- 在Redux中新增
isSliderClearing布尔状态,onSliderClose触发时先将状态设为true,所有异步清理操作执行完成后再重置为false onClickElement触发时先判断isSliderClearing状态,为true则等待状态重置后再执行后续打开、拉取逻辑,也可以直接拦截操作提示用户稍候
示例代码:
const onClickElement = async (itemId) => { // 等待清理操作完成再执行后续逻辑 while(getState().slider.isSliderClearing) { await new Promise(resolve => setTimeout(resolve, 30)) } openSlider() const resData = await fetchSliderDetail(itemId) dispatch(setSliderData(resData)) } const onSliderClose = async () => { dispatch(setSliderClearing(true)) try { await asyncClearTask1() await asyncClearTask2() dispatch(clearSliderAllData()) } finally { dispatch(setSliderClearing(false)) } }
方案3:使用AbortController取消过期任务
如果你的清理逻辑是可取消的网络请求,可以在每次打开新滑块时,主动取消上一次未完成的清理异步任务,直接终止过期逻辑,避免后续错误执行。
内容的提问来源于stack exchange,提问作者Bucur Andrada
相关产品推荐
相关产品推荐

