我刚刚开始使用redux-observable,我在多种方法之间做出相同的决定时遇到了麻烦。下面是两个执行某些逻辑以响应操作的方法的示例:
方法A(史诗):
function epic1(action$){
return action$.ofType(FOO)
.map(action => something(action.payload))
.map(result => ({type: BAR}));
}
function epic2(action$){
return action$.ofType(BAR)
.map(action => something(action.payload));
// potentially returning actions for a third epic, etc.
}
方法B(功能):
function helperFunction(result){
// something that returns an action eventually
}
function singleEpic(action$){
action$.ofType(FOO)
.map(action => something(action.payload))
.map(helperFunction);
}
您可以想象每个模式都会向外扩展,而且功能实际上也很复杂。做方法A有很多开销吗?这些行为是否会在到达epic2
之前通过整个redux循环,这是否在任何人的经历中都是显而易见的?
到目前为止,我绝对想要制作尽可能多的史诗,因为它们最终变得非常小而且简单,但我不确定成本。
答案 0 :(得分:1)
我可以使用redux-saga
从项目中提供我的经验。我认为性能特征和设计权衡非常相似。
在案例A中可能会出现某些性能损失。但是,除非出现真正的错误,否则它不应该是您平均SPA的重要考虑因素。 YMMV如果您正在开发游戏或其他性能密集型的东西。从这个角度来看,创造更少的传奇似乎是微观优化。
我们非常倾向于类似于你所描述的方法B的东西。我们通常会为类似传奇的家庭创建工厂,非常类似于以下示例:
const factory = ({ actionType, mapper, actionCreator }) => (action$) =>
action$.ofType(actionType)
.map(action => mapper(action.payload))
.map(actionCreator);
const epic = factory({
actionType: 'FOO',
mapper: payload => payload + 1,
actionCreator: newPayload => ({ type: 'BAR', payload: newPayload })
});
在这个人为的例子中,它可能没那么有意义,因为抽象的认知开销高于你从中得到的,但你得到了这个想法。我们也采用了非常类似的减速器策略。
但是,如果可能的话,我会警告不要像你用epic1
,epic2
等描述的那样创建动作的瀑布。我相信如果你的代码中存在太多隐含的相互依赖性,它最终将更难调试。虽然在过去的某些框架中可能远不如双向绑定链(例如Ember)。
所以一般来说,我的建议是创造尽可能多的小传奇,创造小帮手来帮助你构建它们。但是对于更复杂的异步流更喜欢更长的更明确的史诗(而不是有太多的合作史诗)。
答案 1 :(得分:0)
方法A会慢一些,因为它会通过reducer和epics的整个redux链。 (史诗本质上是中间件)。这有多慢,重要的程度取决于你认为更易于理解和清晰理解的内容。
我认为,如果你有一个FOO动作,它应该执行一些帮助功能,并最终启动另一个史诗,你不需要三个单独的史诗。如果可能的话,不要开始任何后续行动对我来说更有意义。
然而,如果你确实需要合并史诗,那么创建一个处理'瀑布'类型流的史诗是有意义的。对于这个人为的例子,我肯定不会做方法A.如果你只需要运行一些辅助逻辑,那么直接调用该函数。没有必要向上游行走,所以你可以沿着河流骑行,这样你就可以到达原来的位置。