什么是redux-saga?众所周知,redux-saga是一个中间件。所谓中间件就是为redux提供额外的功能。简而言之,就是在redux中的dispatch中添加一些功能,并进行包装。我们为什么要使用redux-saga?在redux中,如果我们分派一个动作,reducer函数将被调用。函数调度(动作){state=reducer(状态,动作);listeners.forEach(l=>l());返回动作;}那么reducer就是一个没有副作用的纯函数。当我们需要进行异步请求时,这时候redux是不行的,就需要使用redux-saga。redux-saga是如何扩展redux的功能的?中间件的基本格式我们在扩展中间件的时候,会用一个applyMiddleware函数来扩展原来的store.dispatch。functionapplyMiddleare(...middlewares){returnfunction(createStore){returnfunction(reducer,preloadedState){letstore=createStore(reducer,preloadedState);}让派遣;让middlewareAPI={getState:store.getState,dispatch:(action)=>dispatch(action),};让链=中间件。地图((中间件)=>中间件(middlewareAPI));dispatch=compose(...chain)(store.dispatch);返回{...存储,发送,};};};}//compose函数是:functioncompose(funcs){returnfuncs.map((a,b)=>(...args)=>a(b(...args)))}可以是从下面这段代码可以看出,一个中间件接受了一个中间API,也就是store,以及上次转换后的dispatch,然后返回一个新的转换后的dispatch。让chain=middlewares.map((middleware)=>middleware(middlewareAPI));dispatch=compose(...chain)(store.dispatch);所以一个中间件的格式应该是:functionmiddleware(store){return(lastDispatch)=>{return(action)=>{//做一个新的改造//例如logger中间件就是先添加consolelog再添加lastDispatch//比如redux-thunk就是如果action是function怎么处理};};}redux-saga的基本原理:saga使用generator函数产生effect。生成器函数的作用是暂停执行,下次从暂停的地方继续执行。redux-saga的基本使用和具体实现:vredux-saga中的saga分类:rootsaga,即saga的入口,监控saga,即watchsaga,一般通过yieldtake监控saga的具体执行,通过put执行forkcps,etc.//执行sagafunction*workerSaga(){yieldput({type:actionTypes.ADD});}//监控sagafunction*watcherSaga(){yieldtake(actionTypes.ADD_SYNC);yieldworkerSaga();}//entrysagaexportdefaultfunction*rootSaga(){yieldwatcherSaga();}我们知道在使用redux-saga的时候,我们使用createSagaMiddleware创建一个saga函数中间件,然后在saga函数中添加一个run属性,然后执行它在调用applyMiddlewaresaga之后。运行(rootsaga)。在saga.run时,我们将入口saga放入redux-saga的逻辑程序中执行。下面我们来思考一下这个过程应该如何实现:首先createSagaMiddleware是创建saga的中间件,按照我上面说的中间件格式,所以createSagaMiddleware应该这样写functioncreateSagaMiddleware(){functionsagaMiddleware({getState,dispatch}){返回函数(lastDispatch){返回函数(action){constresult=lastDispatch(action);返回结果;}}}returnsagaMiddleware;}然后我们需要在sagaMiddleware中添加一个run函数,在run函数中我们执行了一个runsaga函数。这是一个类似于co的库,它会递归调用生成器函数,直到it.next()返回的done值为false。在此期间,不同类型的效果器会进行不同的处理,从而实现了效果器的异步执行。sagaMiddleware.run=function(...args){runSaga(...args)}导出默认函数runSaga(env,saga){let{channel,dispatch}=env;让它=typeofsaga==='function'?saga():saga;//yieldfork时直接执行runsaga()。//所以saga可能不是一个函数functionnext(value){let{value:effect,done}=it.next(value);if(!done){if(typeofeffect[Symbol.iterator]==='function'){//这种情况是yield后面跟着一个saga,比如yieldwatchSaga()runSaga(env,effect);next();//不会阻止当前saga继续往回走}elseif(effectinstanceofPromise){//如果产生新的promiseeffect.then(next);}else{switch(effect.type){caseeffectTypes.TAKE://...caseeffectTypes。放://...中断;默认值:中断;}}}}next();}通过effect.type处理不同类型的函数take:listenonceusage:yieldtake(actiontype)listenonce,然后继续向下执行。caseeffectTypes.TAKE:channel.once(effect.actionType,next);其中channel是一个类似于nodeEventEmitter的发布-订阅模型,我们可以实现一个。函数通道(){让听众=[];functiononce(type,listener){listener.type=type;listener.cancel=function(){listeners=listeners.filter((item)=>item!==listener);};listeners.push(监听器);}functionput(action){for(leti=0;i
