实现一个精简的redux-saga主要包括三个部分,首先是通过createSagaMiddelware创建saga中间件sagaMiddelware,第二是sagaMiddelware中实现一个run函数用于绑定要运行的生成器函数,最后是实现副作用函数。
?
1、createSagaMiddelware中间件创建函数
在createSagaMiddelware中会返回一个sagaMiddelware中间件,sagaMiddelware中间件会作为输入参数于redux中间件接口绑定,中间件返回一个函数,函数的输入参数是dispatch函数next和action,该函数会先执行next函数然后执行自己的生成器函数。
function createSagaMiddelware() {
function sagaMiddelware({
getState,dispatch}){
//负责把gernerator执行完毕function run(iterator){
...}sagaMiddelware.run = run;//中间件执行,每次store dispatch的时候都会先来执行返回的函数//该函数输入actionreturn (next) => (action) => {
next(action)//先执行中间件中后面的函数channel.publish(action)//判断是否有take中监听的action要执行}}return sagaMiddelware;
}
export default createSagaMiddelware;
其中channel是用于存储一些中间信息,例如take监测action时会讲action type放到channel中用于帮助监测,如果channel监测到action后会执行生成器的下一个yeild函数,channel函数代码如下:
function createChannel() {
//对象的key为actiontype,value为next函数,//作用就是收到该actiontype后往下运行 let takers={
};///将take要监控的actiontype放到channel的takes对象中function subscribe(actionType,cb) {
takers[actionType]=cb;}function publish(action) {
//得到当前的action是否是take监控的let taker=takers[action.type]if (taker) {
//如果有执行监听函数则删除当前takerlet tmp=taker;//先删除taker = null;tmp(action); //然后执行 }}return {
subscribe,publish};
}
export let channel = createChannel();
2、实现中间件的run函数
中间件的run函数如下:
//负责把gernerator执行完毕
function run(iterator){
//判断iterator是否是函数,是则返回执行后的结果,不是则返回iteratorlet it = typeof iterator == 'function'?iterator():iterator;function next(input){
//it是生成器执行的结果,生成器执行后返回的是一个对象i,通过it.next往后执行到下一个到yeild,调用第一个it.next才算是真正执行let {
value: effect,done}=it.next(input);//当前的it.next返回的是即将执行的这个yeild函数的执行返回值是什么,done表示是否是有yeild函数需要执行//如果有yeild函数等待if(!done){
//genratorif(typeof effect[Symbol.iterator] == 'function'){
run(effect);next();}//判断是否是延迟函数if(isPromise(effect)) {
effect.then(next).catch(error => next(error))}//判断组册事件类型,来处理switch(effect.type){
//注册事件case 'take':let {
actionType}=effect;//将take要监控的actiontype放到channel的takes对象中//对象的key为actiontype,value为next函数,作用就是收到该actiontype后往下运行channel.subscribe(actionType,next);break;//走到put的事件就直接dispatch执行了case 'put':let {
action}=effect;//先dispatch一下dispatch(action);//然后执行下一个yieldnext(action);break;//fork继续执行case 'fork':let {
worker}=effect;run(worker);next();break;//异步执行成功后再nextcase 'call':let {
fn,args}=effect;fn(...args).then(next);break;default:break;}}}//开始执行生成器函数next()
}
3、定义副作用函数
function take(actionType) {
return {
type: 'take',actionType}
}
function put(action) {
return {
type: 'put',action}
}
function fork(worker) {
return {
type: 'fork',worker}
}
function call(fn,...args) {
return {
type: 'call',fn,args}
}
//监听每一个动作类型,当此动作发生的时候执行对应的worker
//takeEvery它会单开一个任务,并不会阻塞当前saga
function* takeEvery(actionType,worker) {
yield fork(function* () {
while (true) {
let action = yield take(actionType);yield worker(action);}})
}function delay(ms, val = true) {
let timeoutIdconst promise = new Promise(resolve => {
timeoutId = setTimeout(() => resolve(val), ms)})promise['CANCEL_PROMISE'] = () => clearTimeout(timeoutId)return promise
}//takerEvery的结果是一个迭代器
//iterator
export {
take,put,takeEvery,call,delay
}