• 微信
当前位置:首页 >> 建站学院 >> Web前端

【前端笔记】js洋葱模型的实现

作者:玄北 时间:2021-10-20 阅读数:425人阅读

首先,什么是洋葱模型?

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

如下图:

洋葱模型

代码如下:

// 洋葱模型顾名思义,指的是方法的执行像洋葱一样,一层一层往里执行,直到中心点后,再一层一层往外出来。
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);

  }};

over~~

头都大了

转载请注明——本文源自【玄北博客】www.xuanbeiweb.cn

免责声明:本站部分文章、数据、图片来自互联网,

如果侵犯了你的权益请来信告知我们删除,否则不承担相应法律责任。邮箱:xuanbei@xuanbeiweb.cn

玄北头像

玄北

Hi~如果您正好看到这里,可以扫一扫微信二维码加我为好友,我是一个喜欢交朋友的人,我知道您也是哦~

玄北微信

发表评论:

评论记录:

暂无评论——欢迎您的点评!