做有追求的coder - Redux进阶compose方法的实现与解析

2,356 阅读3分钟

前言

在使用redux的过程中,不免要用到中间件,用到中间件,就免不了使用compose方法来解决中间件层层嵌套的问题,那么redux中的compose方法实现原来是怎样的呢?

用法

compose(...functions)

这是函数式编程中的方法,为了方便,被放到了 Redux 里。 当需要把多个 store 增强器(中间件) 依次执行的时候,需要用到它。

参数

(arguments): 需要合成的多个函数。预计每个函数都接收一个参数。它的返回值将作为一个参数提供给它左边的函数,以此类推。例外是最右边的参数可以接受多个参数,因为它将为由此产生的函数提供签名。(译者注:compose(funcA, funcB, funcC) 形象为 compose(funcA(funcB(funcC()))))

返回值

(Function): 从右到左把接收到的函数合成后的最终函数。

一个例子

import {componse} from 'redux'
function add1(str) {
	return 1 + str;
}
function add2(str) {
	return 2 + str;
}
function sum(a, b) {
	return a + b;
}
let str = compose(add1,add2,add3)('x','y')
console.log(str)
//输出结果 '12xy'

上面代码compose(add1,add2,add3)('x','y')方法实际上等同于下面的代码

add1(add2(add3('x','y')))

一步步解析compose方法内部的实现,首先从用法compose(add1,add2,add3)('x','y')来看,compose方法的运行结果显然返回的是一个函数.

function compose(...fns){
    return function(...args){ //  args => ['x','y']
        ...处理代码        
    }
}

由于只有最右边的中间件才能接受多个参数,我们先将它取出来,将多个的参数单独传给他 其他的中间件函数都只有一个参数,就是他右侧中间件函数执行之后的返回值

function compose(...fns){
    return function(...args){ //  args => ['x','y']
        let last = fns.pop(); // sum
        fns.reduceRight((val,fn)=>{
            return fn(val)
        },last(...args))
    }
}

我们来分析一下 fns.reduceRight中的运行

fns.reduceRight((val,fn)=>{
    return fn(val)
},last(...args))

第一次 val 为 sum('x','y') fn为 add2

第二次 val 为 add2(sum('x','y')) fn 为 add1

运行结束 返回 add1(add2(sum('x','y')));

这样,compose的运行原理就基本解释清楚了,但是,这个只是redux中compose方法以前的实现方法.现在redux中对于compose的实现换了一种更加优雅的方法

redux中compose方法最新实现

它摒弃了原来将最后一个中间件函数提取出来的方法,直接一行代码将内部逻辑实现了

    function compose(...fns){
        return fns.reduce((a,b)=>(...args)=>a(b(...args)))
    }

我们还是以compose(add1,add2,sum)('x','y')为例对fns.reduce进行解析

    fns.reduce((a,b)=>(...args)=>a(b(...args)))
    //展开
    function compose(...fns){
    	return fns.reduce((a,b)=>{
    		return (...args)=>{
    			return a(b(...args))
    		}
		}
	}
})
//第一次 运行 a为add1 b为add2
//第二次 运行 a为 (...args)=>{
                    return add1(add2(...args))
                }
            b为 sum
//运行结束 返回 
(...args)=>{
	return ((...args)=>{
        		return add1(add2(...args))			
        	})(sum(...args))
}
//为了能更好的区分逻辑,我把这里稍微改一下
(...args2)=>{
    return  ((...args)=>{
                return add1(add2(...args))
            })(sum(...args))
}
//等价于
(...args2)=>{
    add1(add2(sum(...args2)))
}
//args2替换为['x','y']
add1(add2(sum('x','y')))

逻辑总算是理清楚了,真的是有够绕的

结语

每次源码阅读与解析,总是能够在不经意的角落发现令人赞叹的代码,编程的魅力大概就在这里吧

如果觉得还可以,能在诸君的编码之路上带来一点帮助,请点赞鼓励一下,谢谢!