redux源码分析:compose
redux 中间件精化之 compose
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);
})