index.js:
import { channel } from './channel'//promise判断const isPromise = p => {return typeof p.then == 'function' && typeof p.catch == 'function'}function createSagaMiddelware() {function sagaMiddelware({getState,dispatch}){//负责把gernerator执行完毕function run(iterator){//执行得到迭代器,next得到值,可能是器也可能是迭代器let it = typeof iterator == 'function'?iterator():iterator;function next(input){let {value: effect,done}=it.next(input);//如果迭代器没有完成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;channel.subscribe(actionType,next);break;//走到put的事件就直接dispatch执行了case 'put':let {action}=effect;dispatch(action);next(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()}sagaMiddelware.run = run;//中间件执行return (next) => (action) => {next(action)channel.publish(action)}}return sagaMiddelware;}export default createSagaMiddelware;
channel.js
function createChannel() {//对象每一个动作对应一个回调函数let takers={};function subscribe(actionType,cb) {takers[actionType]=cb;}function publish(action) {//监听let taker=takers[action.type]if (taker) {//如果有执行监听函数并且删除监听函数let tmp=taker;taker = null;tmp(action);}}return {subscribe,publish};}export let channel = createChannel();
effect.js
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它会单开一个任务,并不会阻塞当前sagafunction* 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的结果是一个迭代器//iteratorexport {take,put,takeEvery,call,delay}
使用:
app.js:
import React from 'react';import ReactDOM from 'react-dom';import Root from './router';import {createStore, applyMiddleware } from 'redux';import { Provider } from 'react-redux';import createSagaMiddleware from './testSaga/index.js'// import createSagaMiddleware from './saga/index'import { watchIncrementAsync, watchAndLog } from './sagaActions/index'//globe cssimport './style/index.styl';import './style/less.less';import './style/sass.sass';import './style/scss.scss';const initialState = {number: 0,list: []};const incrementReducer = (state = initialState, action) => {switch(action.type) {case 'INCREMENT': {state.number += 1return { ...state }break}case 'DECREMENT': {return {...state,list: action.data.data}break};default: return state;}};const sagaMiddleware = createSagaMiddleware();const store = createStore(incrementReducer,applyMiddleware(sagaMiddleware))sagaMiddleware.run(watchIncrementAsync)// sagaMiddleware.run(watchAndLog)ReactDOM.render(<Provider store={store}><Root /></Provider>,document.getElementById('app'));
sagaAction:
// import { delay } from '../saga'// import { select, call, fork, take, put, takeEvery } from '../saga/effects'import { call, put, takeEvery, take, delay } from '../testSaga/effect'import {GetUserData} from '../fetch/api.js'export function* watchAndLog() {while (true) {const action = yield take('*')const state = yield select()console.log('action', action)console.log('state after', state)}}export function* incrementAsync() {yield delay(1000)yield put({ type: 'INCREMENT' })}export function* indecrementAsyncs({ payload }) {//发起请求 payload是给请求函数的参数const data = yield call(GetUserData, payload);yield put({ type: 'DECREMENT', data })}//发起请求function* fetchUrl(param) {const data = yield call(GetUserData, param); // 指示中间件调用 fetch 异步任务yield put({ type: 'DECREMENT', data }); // 指示中间件发起一个 action 到 Store}export function* watchIncrementAsync() {yield takeEvery('INCREMENT_ASYNC', incrementAsync)yield takeEvery('DECREMENT_ASYNC', indecrementAsyncs)//或者// while(true) {// const action = yield take('FETCH_REQUEST'); // 指示中间件等待 Store 上指定的 action,即监听 action// yield fork(fetchUrl, action.payload); // 指示中间件以无阻塞调用方式执行 fetchUrl// }}
发起事件:
onClick() {this.props.dispatch({type: 'DECREMENT_ASYNC',// type: 'FETCH_REQUEST',//参数的传递payload: {name: 'test',s:11}})}
