Redux-Saga中的异常处理
Redux-Saga
是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)的 library,它的目标是让副作用管理更容易,执行更高效,测试更简单,在处理故障时更容易。不可避免的是,effects中可能会出现异常,比如一个call API请求,对于异常又该如何处理呢。这篇文章聚焦于将这点。
异常不处理?
贴一个effects,连续三次
call后端。
假如第二次
请求getBooks
出错,还会打印step 2
吗?
如上没有打印,也就是请求异常,整个程序effects执行就会中断。
单个请求异常处理
在effects中对于异常,我们需要使用try catch
如上,getBooks请求进行了异常捕捉,这样做就可以吞掉这个错误,进而可以正常执行接下来的请求了。所以控制台对于step1,step2,step3都正常打印
什么算异常?
对于一个后端请求,200,400,404,500都是常见response code,那么什么请求才会在异常中要捕获?
Demo中我使用的Axios,so这里要看它了。开启源码阅读,源码中有个validateStatus函数,具体实现如下。可以看出200到300之间的正常,其它的抛出异常,300段的浏览器在接收后都会自行重定向。就是说我们400,500的错误才会在catch中捕获。
1 | validateStatus: function validateStatus(status) { |
1 | module.exports = function settle(resolve, reject, response) { |
要看axios相关源码 戳这里
单个Effects异常处理
单个请求报错,effetcts也会挂掉,进而整个Saga树挂掉,整个App可能崩溃,那么为了确保WEB安全,我们需要让effects健壮些,so我们来做个wrapper。
1 | import { call } from 'redux-saga/effects'; |
effects上挂载wrapper
单个effects异常,整个saga监听中止
如上,我们增加saga 打印信息,在组件中,我们连续调用两次同一个action
查看日志,会发现其实,打印信息只有一个
造个捕捉异常轮子
很多时候,我们为了确保业务系统的健壮性,需要保证,单个effects执行出现故障后,不造成监听中止,so,增加wrapper。
1 | import { call } from 'redux-saga/effects'; |
然后在effects中调用
1 | function* mySaga() { |
效果
即使第一个effects出现问题,并不会影响第二个的执行
effects统一处理?
如上,对于单个effect增加safe函数,挺方便。但有没有一劳永逸的办法呢?毕竟safe很多的话,一眼望去不都是重复代码嘛!说好的DRY!
经过询问大神及查看Saga源码,找到了办法
1 | const effectMiddleware = next => effect => { |
如上进行设定,对于单个effect就不需要加safe了,一劳永逸。
注意!
effectMiddlewares
这个配置项是1.0.0
引入的新特性,要用,就需要升级了。
1.0.0新特性查看,戳这里
单个effect的type是fork?
- 是的,查看saga源码,会知道effect 的type有15种[TAKE,PUT,ALL,FORK等]
- 我们takeEvery或者takeLatest实际上就是发起了Fork类型的effect
异常信息不友好?
是的,通过异常信息,目前只能知道action名称,具体绑定的effects中错误代码的行号信息是不清楚的。
写在最后
我们是可以增加safe确保报错不影响其它saga执行,但是想想,为什么会报错,异常就一定是不安全,而不报错就是安全了吗?我们容错的同时,其实是掩盖了问题,从而降低了应用的安全性,假如不加safe,我们利用程序解决了这个不该爆发的错误不是更好吗?这点值得我们想想。
不论是saga还是其它类库,轮子虽好,但都有这样那样的问题,我们除了熟悉轮子解决我们的业务问题外,更多的是思考其背后的原理和适当造些更趁手的轮子吧。加油!