写一个redux-saga-1:saga基本结构
saga使用方法:
将异步操作(副作用)放在yield
后面,操作完成后,saga会自动继续执行接下来的代码。
1 | let sagaMiddleware = createSagaMiddleware(); |
所有一切的入口就在这一句:
1 | sagaMiddleware.run(rootSaga) |
一句话:run()
方法启动saga
saga结构大致有以下几个部分:
sagaMiddlewareFactory:工厂方法,用来创建sagaMiddleware中间件
run:程序入口,将action传递到下一个中间件,同时启动rootSaga,并将rootSaga执行后返回的iterator传递给proc继续执行
proc:主要部分,用来执行Generator运行后产生的Iterator,负责触发iterator.next(),并根据每次执行返回的结果选择对应的runner来处理。
task:proc方法运行后的返回值,代表一次saga任务。
effects(位于io.js文件中):定义用来产生effect的方法,例如我们用的
take
,put
等方法,这些方法返回的结果都是一个effect。一个effect的结构如下:1
2
3
4
5
6
7{
payload:{
fn, context
// ... 需要传给effectRunner的参数
},
type: effectType // TAKE, PUT, CALL等effectRunner(位于effectRunnerMap.js文件中):这部分定义了用来执行每种类型effect的方法,例如,
take()
操作产生的effect需要takeEffectRunner()
方法来执行channel(位于channel.js文件中):通道定义文件,通道可用于saga之间的通信和缓存消息
forkQueue(位于forkQueue.js文件中):定义了管理fork task的队列,
fork()
方法会创建另一个task,产生的task会由forkQueue来管理util(位于utils.js文件中):定义了一些工具方法,如
resolvePromise()
、remove()
等。
下面写一下saga的工厂函数:sagaMiddlewareFactory()
,用来创建saga中间件。
1 |
|
上面是sagaMiddlewareFactory()
的大概样子。
saga中间件在获取到action后,需要决定是否要采取相应的动作,因此事先我们需要将action以及需要采取的动作注册到saga中间件某处—–如上所说我们将action以及需要采取的动作注册到channel中。(个人理解:想象一下,有个管道,action和对应的动作像“滤网”一样存在于管道中。当外界的action从管道中流过时,那些有相同action的滤网就会被击中,对应的操作就会被触发,同时管道中action被击中一次后就会被移除管道)
来定义一个channel。channel要有一个可以注册action和动作的方法,还要有一个能将接收到的action推入管道的方法。
1 | function stdChannel(){ |
来将管道应用到sagaMiddlewareFactory()
中:
1 | function sagaMiddlewareFactory(){ |
本节代码地址:https://github.com/xusanduo08/easy-saga/tree/master/%E5%86%99%E4%B8%80%E4%B8%AAredux-saga-1