JS可复用代码与DRY Saga:生成器嵌套是否存在潜在异常?
生成器嵌套在Redux Saga Catch块中是否会引发意外行为?
首先得明确说:是的,你现在的写法肯定会出现意外行为,而且问题还挺关键——你重构的errorHandler里的逻辑根本不会被执行。
咱们来拆解下原因:
- Redux Saga的中间件只会识别并处理它自己的Effect对象(比如
put()、call()这些函数返回的就是Effect)。 - 你现在在catch块里写
yield errorHandler(),这里errorHandler()调用后返回的是一个生成器对象,不是Redux Saga的Effect。中间件看到这个生成器对象,不会去遍历执行它内部的put和call逻辑,相当于这段代码完全没起作用。
那正确的写法应该是怎样的?有两种靠谱的方式:
方式1:用Redux Saga的call Effect调用生成器
这是Redux Saga官方推荐的做法,能让中间件正确处理嵌套的生成器逻辑:
try { // 业务逻辑 } catch (err) { yield call(errorHandler); }
方式2:用ES6的yield*委托生成器
这是原生JS的生成器语法,会把嵌套生成器的执行委托给外层:
try { // 业务逻辑 } catch (err) { yield* errorHandler(); }
不过这种写法Redux Saga官方不太推荐,因为yield*不属于Saga的Effect体系,不利于后续的测试和调试(比如Saga Monitor无法追踪到yield*内部的步骤)。
额外提醒
如果你的errorHandler需要接收错误信息(比如要把错误内容打日志),还可以给它传参:
// 改造errorHandler function* errorHandler(error){ console.error('请求失败:', error); yield put({ type: LOAD_DATA_ERROR, failed: true }); yield call(delay, 2000); yield put({ type: LOAD_DATA_ERROR, failed: false }); } // 调用时传参 yield call(errorHandler, err);
总的来说,你当前的写法最大的意外就是errorHandler里的错误提示逻辑完全不生效,改成上面两种正确的调用方式就能解决问题啦。
内容的提问来源于stack exchange,提问作者Seemax
相关产品推荐
相关产品推荐

