手写Redux-Saga源码 (5)

可以看到当我们使用effect时,他的返回值就仅仅是一个描述当前任务的对象,这就让我们的单元测试好写很多。因为我们的代码在不同的环境下运行可能会产生不同的结果,特别是这些异步请求,我们写单元测试时来造这些数据也会很麻烦。但是如果你使用Redux-Saga的effect,每次你代码运行的时候得到的都是一个任务描述对象,这个对象是稳定的,不受运行结果影响,也就不需要针对这个造测试数据了,大大减少了工作量。

effects对应的源码文件看这里:https://github.com/redux-saga/redux-saga/blob/master/packages/core/src/internal/io.js

takeEvery

我们前面还用到了takeEvery来处理同时发起的多个请求,这个API是一个高级API,是封装前面的take和fork来实现的,官方源码又构造了一个新的迭代器来组合他们,不是很直观。官方文档中的这种写法反而很好理解,我这里采用文档中的这种写法:

export function takeEvery(pattern, saga) { function* takeEveryHelper() { while (true) { yield take(pattern); yield fork(saga); } } return fork(takeEveryHelper); }

上面这段代码就很好理解了,我们一个死循环不停的监听pattern,即目标事件,当目标事件过来的时候,就执行对应的saga,然后又进入下一次循环继续监听pattern。

总结

到这里我们例子中用到的API已经全部自己实现了,我们可以用自己的这个Redux-Saga来替换官方的了,只是我们只实现了他的一部分功能,还有很多功能没有实现,不过这已经不妨碍我们理解他的基本原理了。再来回顾下他的主要要点:

Redux-Saga其实也是一个发布订阅模式,管理事件的地方是channel,两个重点API:take和put。

take是注册一个事件到channel上,当事件过来时触发回调,需要注意的是,这里的回调仅仅是迭代器的next,并不是具体响应事件的函数。也就是说take的意思就是:我在等某某事件,这个事件来之前不许往下走,来了后就可以往下走了。

put是发出事件,他是使用Redux dispatch发出事件的,也就是说put的事件会被Redux和Redux-Saga同时响应。

Redux-Saga增强了Redux的dispatch函数,在dispatch的同时会触发channel.put,也就是让Redux-Saga也响应回调。

我们调用的effects和真正实现功能的函数是分开的,表层调用的effects只会返回一个简单的对象,这个对象描述了当前任务,他是稳定的,所以基于effects的单元测试很好写。

当拿到effects返回的对象后,我们再根据他的type去找对应的处理函数来进行处理。

整个Redux-Saga都是基于Generator的,每往下走一步都需要手动调用next,这样当他执行到中途的时候我们可以根据情况不再继续调用next,这其实就相当于将当前任务cancel了。

本文可运行的代码已经上传到GitHub,可以拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/React/redux-saga

参考资料

Redux-Saga官方文档:https://redux-saga.js.org/

Redux-Saga源码地址: https://github.com/redux-saga/redux-saga/tree/master/packages/core/src

文章的最后,感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,请不要吝啬你的赞和GitHub小星星,你的支持是作者持续创作的动力。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsspgd.html