js洋葱模型的实现

3,820次阅读
没有评论

共计 2302 个字符,预计需要花费 6 分钟才能阅读完成。

前言

洋葱模型指的是方法的执行像洋葱一样,一层一层往里执行,直到中心点后,再一层一层往外出来。

如下图:
enter image description here

代码实现

// 洋葱模型顾名思义,指的是方法的执行像洋葱一样,一层一层往里执行,直到中心点后,再一层一层往外出来。const middleware = [];
middleware.push(function (next) {console.log(1);
    next();
    console.log(4);
});
middleware.push(function (next) {console.log(2);
    next();
    console.log(5);
});
middleware.push(function (next) {console.log(3);
    next();
    console.log(6);
});

function compose(middleware) {return function () {function dispatch(i) {const fn = middleware[i];
            if (typeof fn === 'function') {
                i++;
                const next = function () {dispatch(i);
                };
                fn(next);
            }
        }

        dispatch(0);
    }
}

// 调用
compose(middleware)();

分析

compose 必须返回的是一个函数,并且每次函数执行,都需要将下一个函数作为参数传给它,这样才能够让方法一层层的执行下去,直到最里面一层:

function compose(middleware) {return function(args){dispatch(0);
    function dispatch(index){const fn = middleware[index] || args;
      if(typeof fn !== "function") return;
      const next = ()=> dispatch(index+1);
      fn(next);
    }
  }
};

异步函数也能的处理:

function asyncFn() {return new Promise((resolve, reject) => {setTimeout(() => {console.log("delay...");
      resolve();}, 1000);
  });
}

const fn1 = async (next) => {console.log(1)
  await next()
  console.log(2)
}

const fn2 = async (next) => {console.log(3)
  await asyncFn();
  await next()
  console.log(4)
}

const fn3 = async (next) => {console.log(5)
  await next()
  console.log(6)
};

function compose(middleware) {return function (args) {dispatch(0);
    function dispatch(index) {const fn = middleware[index] || args;
      if (typeof fn !== "function") return Promise.resolve();
      const next = () => dispatch(index + 1);

      // 给执行函数添加返回成功的 Promise.resolve
      return Promise.resolve(fn(next))
    }
  }
};

compose([fn1,fn2,fn3])();

Redux 中间件

redux 的中间件 compose 函数如下:

function compose(middleware) {return middleware.reduce((total, next) => (...args) => total(next(...args)));
}

redux 的中间件函数很不好理解,这里可以将它拆开进行分析:

const fn1 = (next) => {return ()=>{console.log(1)
    next()
    console.log(2)
  }
}

const fn2 = (next) => {return ()=>{console.log(3)
    next()
    console.log(4)
  }
}

const fn3 = (next) => {return ()=>{console.log(5)
    next()
    console.log(6)
  }
}

const dispatch = compose([fn1,fn2,fn3])(()=> console.log("dispatch"));

dispatch();

middleware 经过 reduce 叠加,每次都将上一次的结果返回给下一个函数作参数:

// 第 1 次 reduce 的返回值,变成 total 传递到下一次
arg => fn1(() => fn2(arg));

// 第 2 次 reduce 的返回值,继续作为下一次的 total
arg => (arg => fn1(() => fn2(arg)))(() => fn3(arg));

或者将 compose 转成比较好理解的函数迭代形式:

function compose(middleware) {return function(cb) {function dispatch(index){const fn = middleware[index];
      const next = ()=>dispatch(index+1); // 下一次的函数执行
      // 如果不存在下一个函数了,拿到传参里面的函数执行,这里需要保证传参是一个函数,对应的是 redux 里面的 dispatch 参数
      fn ? fn(next)() : cb() 
    }

    // 最终返回一个函数
    return ()=> dispatch(0);

  }
};

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于1970-01-01发表,共计2302字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)