当前位置: 代码迷 >> 综合 >> 如何实现一个精简版的redux-saga
  详细解决方案

如何实现一个精简版的redux-saga

热度:14   发布时间:2023-12-03 09:34:07.0

实现一个精简的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
}