redux-saga简易实现

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){
                    //genrator
                    if(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;
                        //异步执行成功后再next
                        case '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它会单开一个任务,并不会阻塞当前saga
function* takeEvery(actionType,worker) {
	yield fork(function* () {
		while (true) {
			let action = yield take(actionType);
			yield worker(action);
		}
	})
}

function delay(ms, val = true) {
    let timeoutId
    const promise = new Promise(resolve => {
      timeoutId = setTimeout(() => resolve(val), ms)
    })
  
    promise['CANCEL_PROMISE'] = () => clearTimeout(timeoutId)
  
    return promise
}

//takerEvery的结果是一个迭代器
//iterator
export {
	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 css
import './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 += 1
      return { ...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
      }
    })    
  }

执行流程分析:
初始化阶段:
执行createSagaMiddelware 返回 sagaMiddelware
执行 saga run方法 传入的是自定义的 watchIncrementAsync函数:这里面是takeEvery命令
拿到 iterator (watchIncrementAsync)并执行一下
初次执行一下 next 函数,此时next中 input参数为undefined
执行generator 的 next 获取 watchIncrementAsync中 第一个yield(takeEvery类型)的值
如果里面是iterator则继续run next 最终走到 fork ,fork里面因为是generator函数 则继续执行 run next
走到 type take 往channel监听器中添加 actionType 和 netx函数回调 这样dispatch 就可以执行这个next回调
初始化阶段完毕

点击dispatch执行阶段:
dispatch takeEvery中的类型 找到初始化阶段添加注册的此类型并执行 netx 回调
然后it.next(input) 触发的是 yield worker(action); worker就是incrementAsync函数因为他是generator函数 所以会继续执行run()后 再next就可以继续yield
如果其中有 自定义 delay 延迟函数,则等待then结束再回调 next
worker此时是逻辑执行函数如果是
yield put 就直接执行 dispatch(action); 并且next一下,后面可能有多个yield
yield call 执行fn(…args).then(next);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值