如何在Redux-Saga中使用带回调的异步函数(以Fingerprint2为例)
解决Redux-Saga调用回调式异步函数阻塞的问题
嘿,这个问题我太熟了!之前在处理回调式异步函数和Redux-Saga结合的时候也踩过同样的坑——直接用yield call调用Fingerprint2的get方法会一直阻塞,根本拿不到结果。原因很简单:Redux-Saga的call effect默认是为返回Promise的异步函数或者同步函数设计的,而Fingerprint2.get是基于回调的,它不会返回任何值,Saga自然会一直等着,永远等不到结果。
下面给你两种靠谱的解决办法,任选其一就行:
方法一:把回调函数包装成Promise
这是最通用的做法,把基于回调的异步逻辑转换成Promise风格,让Redux-Saga能正确识别并等待结果。
先写一个包装函数:
// 包装Fingerprint2.get为Promise函数 function getFingerprint() { return new Promise((resolve, reject) => { new Fingerprint2().get((result, components) => { if (result) { // 把结果和组件数据一起resolve出去 resolve({ result, components }); } else { // 如果获取失败,reject一个错误 reject(new Error('Failed to retrieve device fingerprint')); } }); }); }
然后在你的Saga里调用这个包装后的函数:
import { call, put } from 'redux-saga/effects'; function* fetchFingerprintSaga() { try { // 用call等待Promise resolve,拿到结果 const { result, components } = yield call(getFingerprint); // 拿到结果后,dispatch成功的action yield put({ type: 'FINGERPRINT_FETCH_SUCCESS', payload: { fingerprint: result, components } }); } catch (error) { // 处理错误情况 yield put({ type: 'FINGERPRINT_FETCH_FAILURE', error: error.message }); } }
方法二:使用Redux-Saga的cps Effect
Redux-Saga专门提供了cps effect来处理**延续传递风格(CPS)**的回调函数,也就是最后一个参数是回调的函数,这样你不用手动包装Promise,直接用原生回调逻辑就行。
注意:cps要求回调函数的格式是(error, result),但Fingerprint2的get回调是(result, components),没有错误参数,所以我们需要稍微调整一下回调的格式:
import { cps, put } from 'redux-saga/effects'; function* fetchFingerprintSaga() { try { // 使用cps处理回调函数 // 我们手动把回调转换成(error, result)的格式 const [result, components] = yield cps((callback) => { new Fingerprint2().get((res, comps) => { // 第一个参数传null表示没有错误,第二个参数传递结果数组 callback(null, [res, comps]); }); }); // 同样dispatch成功action yield put({ type: 'FINGERPRINT_FETCH_SUCCESS', payload: { fingerprint: result, components } }); } catch (error) { yield put({ type: 'FINGERPRINT_FETCH_FAILURE', error: error.message }); } }
两种方法怎么选?
- 如果你的项目里有很多回调式的异步函数,推荐用包装Promise的方式,这样代码风格更统一,也方便复用。
- 如果只是处理这一个函数,用cps会更简洁,不需要额外写包装函数。
内容的提问来源于stack exchange,提问作者OriEng
相关产品推荐
相关产品推荐

