函数式的异步处理

   假设我们有一系列需要调用的网络请求,有的并行,有点串行,有的需要处理异常,那么如何打造这样一条执行链呢?

先模拟一些网络请求。

let R= require('ramda');

const getUser = (userId) =>  new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve({users: {
            JOE: {
              name: 'Joe',
              followers: ['STEVE', 'SUZY']
            }
          }})
    }, 500);
});
const getNameList = () => new Promise((resolve,reject)=>{
    setTimeout(() => {
        resolve([
            {name:'name1'},
            {name:'name2'},
            {name:'name3'}
        ])
    }, 400);
});

const getProductByUserName = (name) => new Promise((resolve,reject)=>{
    setTimeout(() => {
        // reject(new Error('nothing'))
        resolve('success');
    }, 1000);
})

我们假设第一个串行,后两个并行(并且捕获错误)

1.命令式写法:

const getResult = async (userId)=> {
    let {users:{JOE:{name}}} = await getUser('userId');
    //捕获错误
    let tasks = [getProductByUserName(name),getNameList()].map(v=>v.catch(err=>err));
    //并发执行
    return Promise.all(tasks);
    //不用PromiseAll的写法:
    //return [await p1,await p2,await p3];
}
const result = getResult().then((v)=>console.log(v));

2.函数式写法:

1.使用composeP,composeP是针对promise对象的组合子(自动将下一个调用放在then里面)

//并发执行
const parallel = R.compose(
    (v)=>Promise.all(v),//这样转一下是因为直接传入Promise.all,node下会报错,原因不明
    (v)=>[getNameList(),getProductByUserName(v).catch(err=>err)],
    R.path(['users','JOE','name'])
)
const getResult = R.composeP(
    parallel,
    getUser
);

const result = getResult().then((v)=>console.log(v));

但是这样写也并不怎么清晰,我们尝试创建一个通用的并发执行的方法。

//并行执行promise,该方法接受两个参数,第一个是promise方法数组,第二个是以上方法需要的参数,方法和参数是一一对应的,不需要参数的方法,需放在数组末尾。
//并行promise
const parallel = (...Ps) =>  R.compose(
                                (v)=>Promise.all(v),
                                R.map(R.otherwise(R.identity)),
                                (...params)=>R.reduce((arr,fn)=>[...arr,fn(params.shift())],[],Ps)
                            )

重新组织我们的调用:

const getResult = R.composeP(
    parallel(getProductByUserName,getNameList),
    R.path(['users','JOE','name']),
    getUser
);

const time = new Date();
getResult('userId').then((result)=>{
    console.log("time:",new Date() - time);
    console.log("TCL: result", result)
}).catch(err=>console.log(err)) 

这样的实现可以用清晰的代码处理复杂的异步调用(即使再复杂,也只是增加了composeP组合的长度而已)

(以上代码都经过测试,直接可用。)之后想讲一下函数提升。

你可能感兴趣的:(函数式的异步处理)