React之reduce实现compose和中间件

reduce实现compose和中间件

函数的深度嵌套调用

通常当下一个调用的函数需要使用到上一个函数执行结果的时候,我们一般会这么做:

例如 吃一次饭:

javascript 复制代码
// 买食物
function buyFood(moeny) {
    return 'original food'
}
// 处理食材
function dealFood(originalFood) {
    return 'ingredients'
}
// 烹饪
function cookFood(ingredients) {
    return 'food'
}
// 吃
function eat(food){}

我们大约需要经历这些步骤,那么一次午饭我们这样:eat(cookFood(dealFood(buyFood(moeny)))),吃一次晚饭:eat(cookFood(dealFood(buyFood(moeny))))...

这种方式不仅增大代码量,更增加阅读和维护的难度;如果业务突然有了改动:一家人吃饭,你怎么能做好了自己就开吃,你得喊家人一起吃对吧?

那么烹饪和吃之间我们需要加一个:

javascript 复制代码
// 喊家人吃饭
function callFamily(ingredients){
    return 'Family'
}

更好得方式肯定是整合封装一下:

javascript 复制代码
function eatMeal(money){
    return eat(cookFood(dealFood(buyFood(moeny))))
}

这样调用的时候,也只需要eatMeal(money),需要callFamily也能直接修改eatMeal即可。但是这样,如果更多的嵌套,就有更多的层叠关系。而我们希望通过类似这样的关系来描述:step1 => step2 => step3 ..

通过reduce实现compose

javascript 复制代码
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

我们需要的结果类似这样:

javascript 复制代码
[step1,step2,step3,step4 ... ].reduce(function(arg,fn){
    return fn(arg)
},arg)

传入一个参数arg,顺序执行数组中的函数,并且后续每一次的入参都是上一步的结果,执行完毕后返回结果。

封装一下:

javascript 复制代码
function compose(fns, arg) {
    Array.prototype.reduce.call(fns, (pre, cur) => {
        return cur(pre)
    }, arg)
}
compose([step1,step2,step3],arg)

但是和第一次问题一样,每一次调用都必须带上所有步骤,不利于编码和维护。

我们需要的是一次定义,多次调用时候只传入参数:

javascript 复制代码
function compose() {
    var fns = arguments;
    return function (arg) {
        return Array.prototype.reduce.call(fns, (pre, cur) => {
            return cur(pre)
        }, arg)
    }
}
function add(num) {
    var result = num + 1;
    console.log(result)
    return result;
}
var add3Times = compose(add, add, add)
console.log(add3Times(2))

再对比网上流传的compose:

javascript 复制代码
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)))
}

多了两个判断:判断没有传入的函数和传入一个函数的时候处理,并且和上面的实现不同,reduce每一步返回的并不是上一步的结果,而是一个函数,最后一样返回一个函数。

第一种情况返回的函数中,函数体内包括reduce的执行,所以后续每次调用都需要重新reduce然后返回结果,并且因为占用arguments,所以compose的执行栈也会一直存在内存中;而第二种返回的是已经经过reduce组装之后的函数,不再占用,所以原来的执行栈可以释放。

修改一下:

javascript 复制代码
function compose() {
    var fns = arguments;
    return Array.prototype.reduce.call(fns, (pre, cur) => {
        return (arg) => {
            return cur(pre(arg))
        }
    })
}

中间件

中间件就是一个函数,可以通过中间件组合成一个最终你想要的逻辑函数。

相关推荐
刘发财3 小时前
前端2秒生成500页矢量PDF,rust真的强到没朋友
前端·javascript·rust
梦想平凡4 小时前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
kyriewen8 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员
mONESY9 小时前
LangGraph.js 从零上手:把 Agent 工作流从一条线变成一张网
javascript
默_笙9 小时前
⚓ AI 的"官方答题卡":withStructuredOutput 与结构化输出的终局之战
前端·javascript
我家猫叫佩奇11 小时前
🦭 厌倦了千篇一律的线性图标?Naive Icons 正式开源
前端·javascript·css
晚安日记wanna11 小时前
SSR 为什么不适合登录态从水合冲突到缓存串号
前端·react.js·面试
梦诺13 小时前
vue3 keepAlive+记录滚动条
前端·javascript·vue.js
天若有情67314 小时前
开源轻量双语工具|一键批量查询 NPM 包历史下载量,支持按作者批量统计
javascript·npm·github pages·开源工具·netlify·前端开源·npm克隆量
福兮说16 小时前
纯前端把图片压缩到指定体积:canvas.toBlob 配合二分查找
前端·javascript·canvas·图片处理