async js 返回值_js 中的洋葱模型

来源:SegmentFault 思否

作者:chenwl

这篇文章探讨js的洋葱模型以它的实现原理,洋葱模型顾名思义,指的是方法的执行像洋葱一样,一层一层往里执行,直到中心点后,再一层一层往外出来。

50ae6bc7472018dc19e13a9ee028dba7.png

上面的图片取自koa中间件的流程控制图,react-redux的中间件也采用了一样的原理。

let fn1 = (next) => {  console.log(1)  next()  console.log(2)}let fn2 = (next) => {  console.log(3)  next()  console.log(4)}let fn3 = (next) => {  console.log(5)  next()  console.log(6)}const middlewares = [fn1, fn2, fn3];compose(middlewares)();/* result:135642*/

合并后的middlewares数组,经过compose处理打印出来的结果是:1、3、5、6、4、2,我们可以想到compose函数回的函数里面是怎么执行的:

        +----------------------------------------------------------------------------------+        |                                                                                  |        |                              fn1                                                 |        |                                                                                  |        |          +-----------------------------------------------------------+           |        |          |                                                           |           |        |          |                    fn2                                    |           |        |          |                                                           |           |        |          |            +---------------------------------+            |           |        |          |            |                                 |            |           |        | action   |  action    |        fn3                      |    action  |   action  |        | 1        |    3       |                                 |      4     |     2     |        |          |            |   action              action    |            |           |        |          |            |     5                   6       |            |           |        |          |            |                                 |            |           |+----------------------------------------------------------------------------------------------->        |          |            |                                 |            |           |        |          |            |                                 |            |           |        |          |            +---------------------------------+            |           |        |          +-----------------------------------------------------------+           |        +----------------------------------------------------------------------------------+

那么我们就开始编写compose函数,首先它必须返回的是一个函数,并且每次函数执行,都需要将下一个函数作为参数传给它,这样才能够让方法一层层的执行下去,直到最里面一层:

function compose(middlewarw) {  return function(args){    dispatch(0);    function dispatch(index){      let fn = middlewarw[index] || args;      if(typeof fn !== "function") return;      let next = ()=> dispatch(index+1);      fn(next);    }  }};

当然我们也希望碰上异步函数,也能正常的执行:

function asyncFn() {  return new Promise((resolve, reject) => {    setTimeout(() => {      console.log("delay...");      resolve();    }, 1000);  });}let fn1 = async (next) => {  console.log(1)  await next()  console.log(2)}let fn2 = async (next) => {  console.log(3)  await asyncFn();  await next()  console.log(4)}let fn3 = async (next) => {  console.log(5)  await next()  console.log(6)};function compose(middlewarw) {  return function (args) {    dispatch(0);    function dispatch(index) {      let fn = middlewarw[index] || args;      if (typeof fn !== "function") return Promise.resolve();      let next = () => dispatch(index + 1);      // 给执行函数添加返回成功的Promise.resolve      return Promise.resolve(fn(next))    }  }};compose([fn1,fn2,fn3])();

react-redux 的中间件实现

react-redux的中间件是这样实现compose函数的:

function compose(middlewarw) {  return middlewarw.reduce((total, next) => (...args) => total(next(...args)));}

react-redux中间件执行的函数很不好理解,不过我们可以拆开它里面的函数来一步步分析:

let fn1 = (next) => {  return ()=>{    console.log(1)    next()    console.log(2)  }}let fn2 = (next) => {  return ()=>{    console.log(3)    next()    console.log(4)  }}let fn3 = (next) => {  return ()=>{    console.log(5)    next()    console.log(6)  }}let dispatch = compose([fn1,fn2,fn3])(()=> console.log("dispatch"));dispatch();

middlewarw经过reduce叠加,每次都将上一次的结果返回给下一个函数作参数:

// 第1次 reduce 的返回值,变成 total 传递到下一次arg => fn1(() => fn2(arg));// 第2次 reduce 的返回值,继续作为下一次的 totalarg => (arg => fn1(() => fn2(arg)))(() => fn3(arg));

或者将compose转成比较好理解的函数迭代形式:

function compose(middlewarw) {  return function(cb) {    function dispatch(index){      let fn = middlewarw[index];      let next = ()=>dispatch(index+1); // 下一次的函数执行      // 如果不存在下一个函数了,拿到传参里面的函数执行,这里需要保证传参是一个函数,对应的是redux里面的dispatch参数      fn ? fn(next)() : cb()    }    // 最终返回一个函数    return ()=> dispatch(0);  }};

- END -

bd321986bbaa0c5a50df45461d2e3c5f.png

e6739777fbc6c2b70302b619045ce58e.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值