redux源码分析:compose

redux 中间件精化之 compose
更新于: 2022-11-24 09:06:19

redux版 compose

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

简单描述compose

  • 这里的 compose函数的作用就是,将所有的中间件函数串联起来,中间件1结束,作为参数传入中间件2,被它处理
  • compose 函数的作用就是组合函数的,将函数串联起来执行,将多个函数组合起来,一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行,就会像多米诺骨牌一样推导执行了

举例

比如有这样的需求,要输入一个名字,这个名字有由firstName,lastName组合而成,然后把这个名字全部变成大写输出来,比如输入jack,smith我们就要打印出来,‘HELLO,JACK SMITH’ 。
我们考虑用函数组合的方法来解决这个问题,需要两个函数greeting, toUpper

// 取 lastName
function getLastName(inValue) {
  const parts = inValue.split(" ");
  return parts[0];
}

// 转大写
function upper(inValue) {
  return inValue ? inValue.toUpperCase() : "";
}

// 问好
function sayHi(inValue) {
  return "hello " + inValue;
}

upper(sayHi(getLastName("Fei Zheng"))); 		// HELLO FEI

第1步:2个函数间的 compose

var compose2 = function (f, g) {
  return function (x) {
    return f(g(x));
  };
};

第2步:不限定个数的函数

function compose() {
  var args = [].slice.call(arguments);
  // length = 0
  // length = 1

  // length == 2
  var fn1 = args[0];
  var fnExtra = args.slice(1);
  return fnExtra.reduce((res, current) => {
    return compose2(res, current);
  }, fn1);
}

第3步:2合1版本(这个思路适合很多场景)

function compose() {
  var args = [].slice.call(arguments);
  // length = 0
  // length = 1

  // length == 2
  var fn1 = args[0];
  var fnExtra = args.slice(1);
  return fnExtra.reduce((res, current) => {
    return function (x) {
      return res(current(x));
    };
  }, fn1);
}

第4步:2合1优化版本

function compose22() {
  var args = [].slice.call(arguments);
  // length = 0
  // length = 1

  // length == 2
  var fn1 = args[0];
  var fnExtra = args.slice(1);
  return fnExtra.reduce((res, current) => (x) => res(current(x)), fn1);
}

第5步:reduce的第2个参数 ,如果不传,会取 args[0]

function compose() {
  var args = [].slice.call(arguments);
  // length = 0
  // length = 1

  // length == 2
  return args.reduce((fn1, fn2) => (x) => fn1(fn2(x)));
}

使用

var fn = compose(upper, sayHi, getLastName);
console.log(fn("Fei Zheng"));

一个不错的库 p-pipe

实际上是从左到右的执行,类似于 compose-promise 的原理,方向不同。

yarn add p-pipe@3
const pipe = require('p-pipe');

const addUnicorn = async string => `${string} Unicorn`;
const addRainbow = async string => `${string} Rainbow`;

const pipeline = pipe(addUnicorn, addRainbow);

pipeline('❤️').then(res => {
    console.log(res);
})

参考