compose 以及pipe
compose 和 pipe 是两种常见的函数组合方式,它们用于将多个函数组合成一个新的函数。这两种方式的主要区别在于函数的执行顺序和参数的传递方式
compose 函数通常将函数从右到左组合,也就是说,最右边的函数先执行,然后是紧挨着它的左边的函数,以此类推,直到所有函数都执行完毕。
1
| const compose = (f, g) => x => f(g(x))
|
pipe 函数则通常将函数从左到右组合,这意味着最左边的函数先执行,然后依次执行后面的函数。
1
| const pipe = (f, g) => x => g(f(x));
|
使用
pipe 管道偏向于线性队列 ,一个个任务从左到右执行。 compose 内到外 。本质上可以相互转化
lodash实现 flowRight 、flow, 但是是同步的,异步的如下
1 2 3 4 5 6 7 8 9
| export const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);
export const pipep = (...fns) => async (x) => await fns.reduce(async (acc, fn) => fn(await acc), x);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import * as UTILS from "./utils.js"; import { flowRight, flow } from "lodash-es";
const add = (num) => { return (baseNum) => { return baseNum + num; }; }; const multiply = (num) => { return (baseNum) => { return baseNum * num; }; };
const addAsync = (num) => { return (baseNum) => new Promise((resolve, reject) => { global.setTimeout(() => { if (typeof num === "number") { resolve(baseNum + num); } }, 200); }); }; const multiplyAsync = (num) => { return (baseNum) => new Promise((resolve, reject) => { global.setTimeout(() => { if (typeof num === "number") { resolve(baseNum * num); } }, 200); }); }; const add1 = add(1); const add2 = add(2);
const mul2 = multiply(2); const mul3 = multiply(3);
const addAsync1 = addAsync(1); const addAsync2 = addAsync(2);
const mulAsync2 = multiplyAsync(2); const mulAsync3 = multiplyAsync(3);
console.log("同步 flow"); console.log(flow(add1, mul2)(11)); console.log("异步 pipep"); const result = await UTILS.pipep(addAsync1, mulAsync2)(11); console.log(result);
|
koa- compose
中间件函数 洋葱模型,外层执行到内存,在回溯到外层。所有中间件函数都可以修改和挂载新的变量到context
1 2 3 4 5 6 7 8 9
| const compose = (...middlewares) => (middlewares || []).reverse().reduce( (dispatch, middleware) => { return async (ctx, next) => { return await middleware(ctx, async () => await dispatch(ctx, next)); }; }, async (ctx, next) => (await next) && next(ctx) );
|
koa的源码实现做了中间键的执行次数限制 还有一些针对插件空的处理 ,核心功能类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| const ctxData = { requestId: "1232324", user: { name: "zhangsan", }, };
const tasks1 = async (ctx, next) => { console.log("获取到requestId", ctx.requestId); await next(ctx); console.log("回溯到tasks1", ctx.requestId); };
const tasks2 = async (ctx, next) => { console.log("校验用户名", ctx.user.name); await next(ctx); console.log("回溯到tasks2", ctx.requestId); };
const tasks3 = async (ctx, next) => { console.log("校验用户名", ctx.user.name); ctx.task3Data = "this is task3"; await next(ctx); console.log("回溯到task3", ctx.user.name); };
console.log("开始compose"); const all = UTILS.compose(...[tasks1, tasks2, tasks3]);
const res = await all(ctxData);
console.log(res);
|