Compose函数

1,026 阅读2分钟

前言

Koa中间件机制:Koa中间件机制就是函数式组合概念 Compose的概念,将一组需要顺序执行的 函数复合为一个函数,外层函数的参数实际是内层函数的返回值。

下面我们看一下一个基本函数组合是怎么实现的

两个函数组合

const add = (x, y) => x + y
const square = z => z * z
const fn = (x, y) => square(add(x, y))
console.log(fn(1, 2)) // 9

上面的函数中,add的返回值又传给了square,这样,就组成了一个新的函数,增强了函数的功能,这就是函数组合的基本作用。

现在我们把它组合成一个函数

const compose = (fn1, fn2) => (...args) => fn2(fn1(...args))
const fn = compose(add,square)
fn(1, 2) // 9

我们用compose把两个函数组合成了一个函数。那如果是个多个函数组合成一个函数怎么做呢?

多个函数组合

我们可以用数组模拟的方式实现多个函数的组合

const add = (x, y) => x + y
const square = z => z * z
const compose = (...[first, ...other]) => (...args) => {
    let ret = first(...args);
    other.forEach(fn => {
        ret = fn(ret)
    })
    return ret
}

const fn = compose(add, square)
fn(1, 2) // 9

异步中间件

上面的函数都是同步的,挨个遍历执行即可,如果是异步的函数呢,是一个 promise,我们要支持async + await的中间件,所以我们要等异步结束后,再执行下一个中间 件。

function compose(middlewares) {
    return function() {
        return dispatch(0);
        // 执行第0个
        function dispatch(i) {
            let fn = middlewares[i];
            if (!fn) {
                return Promise.resolve();
            }
            return Promise.resolve(
                fn(function next() {
                    // promise完成后,再执行下一个
                    return dispatch(i + 1);
                })
            );
        }
    };
}
async function fn1(next) {
    console.log("fn1");
    await next();
    console.log("end fn1");
}
async function fn2(next) {
    console.log("fn2");
    await delay();
    await next();
    console.log("end fn2");
}
function fn3(next) {
    console.log("fn3");
}
function delay() {
    return new Promise((reslove, reject) => {
        setTimeout(() => {
            reslove();
        }, 2000);
    });
}
const middlewares = [fn1, fn2, fn3];
const finalFn = compose(middlewares);
finalFn();

输出结果:
fn1
fn2
fn3
end fn2
end fn1