redux里compose函数源码看不太懂

下面是Redux里compose方法源码:

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  const last = funcs[funcs.length - 1]
  const rest = funcs.slice(0, -1)
  return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}

希望能得到各位详细的解析,谢谢

阅读 2.4k
3 个回答

我恰好看过redux源码,顺手答了,redux要结合redux-thunk 和 applyMiddleWare看。

// redux-thunk.js
({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}
// applyMiddleWare.js
const chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)
export default 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)))
}

这个货需要结合redux-thunk看
redux-thunk经过middleWare(middleWareApi)后返回的是const a = next => action => { return next(action) }
假设还有其他中间件, 其他中间件的函数也是 const b = next => action => next(action)
你自己算一算 b(a) 的效果就是compose的效果。

第一个中间件的next是store.dispatch, 第二个的next是第一个函数返回的结果作为next,中间间中的dispatch是中间间都执行完毕后的 action => next(action)。

compose函数是有一点抽象,你可以自己写一个中间件试一试来理解

export default ({ log = false, namespace }) => {
    if (typeof namespace !== 'string') throw new Error('options.namespace must be given.');
    return ({ dispatch, getState }) => next => action => {
        // state 还未发生变化
        const _r = next(action); // dispatch 触发reducer 和 subscription
        // state已经发生变化
        const state = getState();
        if (log) console.log(state);
        sessionStorage.setItem(namespace, JSON.stringify(state));
        return _r; // 其实这个不重要 返回的是action
    }
}

没有看过redux源码,不过看得懂这个compose函数,现在来说说:

首先 compose 传入的是一串不确定个数的function 作为参数,参数个数大于或者等于2,其实执行过程的是调用一串function队列,从右向左调用,从执行compose方法来说明:

compose(fn1 ,fn2, fn3, ...fn[n-2],fn[n-1],fnn)(...args) ;   

上面的执行过程等价于:

 
 fn1(fn2(......(fn[n-2](fn[n-1](fnn(...args))))))

再说的清楚点就是:

 compose(a,b,c,d)(...args) = a(b(c(d(...args))))

楼主去看看Array的原生方法reduce 和 reduceRight,就很快能理解了。


今天去看了一下redux源码,发现写法已经变了,最后一步变成了

 return funcs.reduce((a, b) => (...args) => a(b(...args)))

其实执行过程还是跟上面的一样,只是写法不同而已

了解一下Array的reduce函数就好理解了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题