redux-saga
是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,拜访浏览器缓存等)的 library,它的指标是让副作用治理更容易,执行更高效,测试更简略,在解决故障时更容易。
作为 redux
的中间件,redux-saga
提供了更加优雅的解决异步action
的形式,redux-saga
通过Generator函数来决定每次动作的暂停
、执行
、提早
或勾销
等操作,
一个 saga 就像是应用程序中一个独自的线程,它单独负责解决副作用。
在redux中应用redux-saga
import { createStore, applyMiddleware } from 'redux'import createSagaMiddleware from 'redux-saga'import reducer from './reducers'import mySaga from './sagas'// create the saga middlewareconst sagaMiddleware = createSagaMiddleware()// mount it on the Storeconst store = createStore(reducer,applyMiddleware(sagaMiddleware))// then run the sagasagaMiddleware.run(mySaga)// render the application
Middleware API
createSagaMiddleware
createSagaMiddleware
函数目标是创立sagaMiddleware
中间件,同时咱们也晓得sagaMiddleware
函数绑定了run
办法
function createSagaMiddleware(){ return function sagaMiddleware({dispatch,getState}){ // 给sagaMiddleware绑定run函数 sagaMiddleware.run = function(generator){} // 中间件函数 return (next) => (action) => { next(action); } }}
middleware.run
sagaMiddleware.run = function (generator, callback) { // 判断 generator 是否函数,返回执行后果或者自身 const iterator = typeof generator === "function" ? generator() : generator; // next 函数判断下一次的动作 function next(action){ const { value: effect, done } = iterator.next(); //如果generator实现,则执行回调函数 if(done){ callback && callback(); return; } // 如果 effect 是一个 generator if (typeof effect.next === "function"){ run(effect,next); } // 如果 effect 是一个 Promise,在promise完结后继续执行next if (effect instanceof Promise){ effect.then(next) } } next();}
Effect 创立器
redux-saga
能够看成由一个个的 effect
所组成,effect
代表了每次执行的指令,新建 effects.js
文件用来创立 effect
take
take
函数可能阻塞generator
,只有在中间件action
中触发能力往下执行,这里能够了解成公布订阅的一个操作,能够在外部创立一个channel
函数用来创立公布订阅器:
function createChannel() { let listener = {}; let subscribe = (actionType, callback) => listener[actionType] = callback; let publish = (action) => { if (!listener[action.type]) return; let actionFn = listener[action.type]; delete listener[action.type]; actionFn(action); } return { subscribe, publish };}
const channel = createChannel();...return (next) => (action) => { channel.publish(action); //中间件派发每次action动作 next(action);}...
effects
文件中创立take
函数,导出并申明type
类型:
// effects.jsexport function take(actionType){ return { type:"TAKE", actionType }}
在next
函数中,判断effect
类型,而后订阅actionType
,并将下一次的next
操作传递给订阅函数,当中间件函数中捕捉到action
时,能力触发到下一次的函数执行:
switch (effect.type) { case "TAKE": channel.subscribe(effect.actionType,next); break; }
put
put
办法执行action
操作,间接在effect函数中返回action
,next
函数中截取到并dispatch
:
// effects.jsexport function put(action){ return { type:"PUT", action }}
case "PUT": dispatch(effect.action); next(effect.action); break;
fork
effects
函数中创立fork
:
// effects.jsexport function fork(task) { return { type:"FORK", task }}
在next
中截取到FORK
类型,task
可能是个generator
函数,所以传递给run
办法执行,
并且保留forkTask
,不便前面做勾销工作的操作:
case "FORK": let forkTask = effect.task(); sagaMiddleware.run(forkTask); next(forkTask); break;
cancel
generator
中能够通过return
办法终止工作的执行,所以咱们能够拿到后面fork
保留的generator
,进行终止操作:
// effects.jsexport function cancel(task) { return { type:"CANCEL", task }}
case "CANCEL": effect.task.return('over') break;
takeEvery
takeEvery
能够了解成对fork
的封装,用while
将每一次的工作监听起来:
//effects.jsexport function* takeEvery(actionType,task) { yield fork(function* (){ while(true){ yield take(actionType); yield task(); } })}
call
call
办法承受promise函数并执行:
//effects.jsexport function call(fn,...args) { return { type:"CALL", fn, args }}
所以在next
中,如果是call
类型则在promise完结后才执行下一个next
case "CALL": effect.fn(...effect.args).then(next) break;
cps
call
办法承受回调函数并执行:
//effects.jsexport function cps(fn,...args) { return { type:"CPS", fn, args }}
case "CPS": effect.fn(...effect.args,next); break;
all
all
办法须要等所有的generator
函数执行完能力往下执行
//effects.jsexport function all(fns) { return { type:"ALL", fns }}
/** @params cb [function] 回调函数* @params total [number] 执行数量*/function times(cb, total) { let index = 0; return () => { index++; if (index >= total) { cb && cb(); } }}...case "ALL": const total = effect.fns.length; const over = times(next, total); effect.fns.forEach(fn => run(fn, over)) break;...