Redux Saga带竞态条件的轮询任务如何返回值?
Redux Saga轮询返回值实现方案
针对你的需求,这里提供两种可行的实现方式,核心是让pollTask的返回值能传递到watchStartBackgroundTask的调用方:
方案1:用返回值替代CANCEL_TASK(推荐)
直接让pollTask在结束轮询时返回结果,无需触发CANCEL_TASK,通过race的task分支捕获返回值,再由watchStartBackgroundTask返回给调用方。这种方式逻辑更简洁,避免冗余的action分发。
import { race, call, take } from 'redux-saga/effects' function* pollTask() { while (true) { // 执行轮询逻辑,比如请求接口 const pollData = yield call(api.fetchStatus); // 满足结束条件时直接返回结果,终止轮询 if (pollData.isCompleted) { return pollData; } // 轮询间隔,比如1秒 yield call(delay, 1000); } } function* watchStartBackgroundTask() { // 移除外层的while(true),否则会无限循环无法返回值 const raceResult = yield race({ task: call(pollTask), // 可选:保留外部取消的支持,比如用户主动触发取消 externalCancel: take('EXTERNAL_CANCEL_TASK') }); // 返回轮询结果:如果正常结束,取task分支的值;如果外部取消,值为undefined return raceResult.task; } // 调用示例 function* someBusinessSaga() { const pollStatusResult = yield call(watchStartBackgroundTask); if (pollStatusResult) { console.log('轮询完成,结果:', pollStatusResult); // 后续处理逻辑,比如更新store yield put({ type: 'POLL_SUCCESS', payload: pollStatusResult }); } else { console.log('轮询被外部取消'); } }
方案2:触发CANCEL_TASK同时返回值
如果必须保留CANCEL_TASK(比如其他saga需要监听这个action做清理操作),可以在watchStartBackgroundTask拿到轮询结果后,再分发CANCEL_TASK,避免在pollTask里同时做分发和返回的冗余操作。
import { race, call, take, put } from 'redux-saga/effects' function* pollTask() { while (true) { const pollData = yield call(api.fetchStatus); if (pollData.isCompleted) { return pollData; } yield call(delay, 1000); } } function* watchStartBackgroundTask() { const raceResult = yield race({ task: call(pollTask), externalCancel: take('EXTERNAL_CANCEL_TASK') }); // 仅当轮询正常结束时,触发CANCEL_TASK if (raceResult.task) { yield put({ type: 'CANCEL_TASK' }); } return raceResult.task; } // 调用示例同方案1
关键说明
- 原代码中
watchStartBackgroundTask的外层while(true)会导致无限循环,无法将结果返回给调用方,必须移除(如果需要多次轮询,可以在调用方处理循环逻辑)。 - 方案1无需额外分发action,逻辑更紧凑;方案2兼顾了action分发和返回值需求,适合需要多saga协作的场景。
内容的提问来源于stack exchange,提问作者user3711357
相关产品推荐
相关产品推荐

