关于函数式编程的异步联想和实现

169 阅读2分钟
函数式编程+函数柯里化的使用方式: [juejin.cn/post/739210…]

上篇介绍了函数式编程的基本使用方式,但是组合函数的入参函数,均属于同步函数,碰到异步函数,又没法用了,于是产生了一个思考,如何整一个可以兼容异步函数的组合函数compose

compose函数实现(同步版)

function compose(...args){
    return function(res){
        return args.reduceRight((res,fn)=>{
            return fn(res)
        },res);
    }
}

const getRes = compose(funB, funA);
const res = getRes(xxx);

先回忆同步的组合函数,给compose函数传入多个子函数去执行,会返回的是一个执行函数,执行函数接受一个入参,调用了会从右往左执行子函数,并且每个子函数的返回值,都会作为入参传递给到下一个子函数,直到所有子函数执行完毕;

compose函数实现(异步版)

说到异步,必然先想到Promise,按照同步版本的compose函数实现思路,最终结果应该会是从右往左依次把异步的结果,传递到下一个子函数的位置去执行

我们先来设想一下执行方式

  const asyncCompose = () => {
      return async (arg)=>{
          const resA=await funcA(arg);
          const resB=await funcB(resA);
          const resC=await funcB(resB);
          return resC
      }    
  }

转换一下

  const asyncCompose = () => async (arg)=>{
       return await funcC(await funcB(await funcA(arg)));
  }    

传递执行结果,那自然是用上reducereduceRight

最终版:
const asyncCompose = (...funcs) => 
    funcs.reduceRight((prePromise, curPromise) => {
        return async (...args) => curPromise(await prePromise(...args))
    });

使用demo

const funcA = (message) => new Promise((resolve, reject) => { 
  setTimeout(() => resolve(message + " A"), 1000);}
);
const funcB = (message) => new Promise((resolve, reject) => resolve(message+' B'));
const funcC = (message) => Promise.resolve(message + " C");
const funcD = (message) => message + " D" ;

const fnabcd = asyncCompose(funcD, funcC, funcB, funcA);

fnabcd("举个栗子").then(res=>{
    console.log('log=>res',res);//log=>res 举个栗子 A B C D
})
.catch(e=>{
    console.log('log=>错误',e);
})

错误捕获

  1. 我们把funcB的resolve(message+' B')改成reject(message+' B'),执行到funcB,后面因为进入catch了,不会继续往后执行
const funcA = (message) => new Promise((resolve, reject) => { 
  setTimeout(() => resolve(message + " A"), 1000);}
);
const funcB = (message) => new Promise((resolve, reject) => {
    console.log(message);//举个栗子 A,  是funcA返回的promise的fulfill的结果
    reject(message+' B')
});
const funcC = (message) => Promise.resolve(message + " C");
const funcD = (message) => message + " D" ;

const fnabcd = asyncCompose(funcD, funcC, funcB, funcA);

fnabcd("举个栗子").then(res=>{
    console.log('log=>res',res);
})
.catch(e=>{
    console.log('log=>错误',e);//log=>错误 funcBB-error
})

  1. 我们改一下funcD,增加一些执行会异常代码
const funcA = (message) => new Promise((resolve, reject) => { 
  setTimeout(() => resolve(message + " A"), 1000);}
);
const funcB = (message) => new Promise((resolve, reject) => resolve(message+' B'));
const funcC = (message) => Promise.resolve(message + " C");
const funcD = (message) => message + " D" + a;

const fnabcd = asyncCompose(funcD, funcC, funcB, funcA);

fnabcd("举个栗子").then(res=>{
    console.log('log=>res',res);
})
.catch(e=>{
    console.log('log=>错误',e);//log=>错误 ReferenceError: a is not defined
})

至此,asyncCompose完成,兼容了同步和异步函数