为什么要在Redux-Saga上使用Redux-Observable?


133

我用过Redux-Saga。到目前为止,用它编写的代码很容易推理,除了JS生成器功能不时使我头晕。据我了解,Redux-Observable可以完成类似的处理副作用的工作,但无需使用生成器功能。

但是,来自Redux-Observable的文档并没有提供很多关于为什么它比Redux-Saga优越的意见。我想知道是否不使用生成器功能是使用Redux-Observable的唯一好处。使用Redux-Observable而不是Redux-Saga可能带来什么弊端,陷阱或妥协?提前致谢。


我做了一个有趣但详尽的博客,发现Redux-Saga对于不是一整天都不能生活/饮食/呼吸可观察者的人们来说,Redux-Saga要优于Redux-Observable。我敢肯定,如果整个堆栈都是可观察的,那就太好了。 shift.infinite.red/...
甘特·拉博德

Answers:


236

免责声明:我是redux-observable的作者之一,因此很难做到100%公正。

我们目前没有提供任何理由说明redux-observable比redux-saga更好,因为...不是。😆

tl; dr两者都有优缺点。许多人会发现一种比另一种更为直观,但是如果您不了解RxJS(可观看redux的内容)或生成器/“数据效果”(redux-saga),则两者的学习方式将很复杂。

它们以极其相似的方式解决相同的问题,但是存在一些根本的差异,只有在您充分使用它们后,这些差异才会真正显现出来。

redux-observable几乎将所有东西都推迟到惯用的RxJS。因此,如果您具有RxJS知识(或获得知识),那么学习和使用redux-observable就是非常自然的事情。这也意味着该知识可以转移到redux之外的其他事物上。如果您决定切换到MobX,如果您决定切换到Angular2,并且如果您决定切换到将来的某个热点X,那么RxJS可以帮助您的机会非常大。这是因为RxJS是一个通用的异步库,并且在许多方面都像一种编程语言一样,本身就是整个“响应式编程”范例。RxJS自2012年以来就存在,并开始作为Rx.NET的端口(几乎每种主要语言都有“端口”,这很有用)。

redux-saga本身提供了基于时间的运算符,因此,尽管您以这种过程管理器风格获得的有关生成器和处理副作用的知识是可以转移的,但其他任何主要库中都没有使用实际的运算符和用法。因此,这有点不幸,但它本身不应该成为破坏交易的工具。

它还使用“效果作为数据”(在此进行描述),起初可能很难绕开头脑,但这意味着您的redux-saga代码实际上并没有执行副作用。而是,您使用的帮助器函数会创建类似于任务的对象,这些任务代表了产生副作用的意图,然后内部库为您执行此操作。这使得测试极其容易,而无需模拟,并且对某些人来说非常有吸引力。但是,我个人发现这意味着您的单元测试重新实现了您的传奇的大部分逻辑-使得这些测试对IMO不太有用(这种观点并非所有人都认可)

人们经常问为什么我们对redux-observable不做这样的事情:对我来说,它与常规惯用的Rx从根本上是不兼容的。在Rx中,我们使用类似.debounceTime()这样的运算符封装了反跳所需的逻辑,但是这意味着,如果我们要制作一个实际上不执行反跳的版本,而是有意图地发射任务对象,那么您现在就失去了Rx的强大功能,因为您不能再将运算符链接在一起,因为它们将在该任务对象上进行操作,而不是操作的真实结果。这确实很难优雅地解释。再次需要对Rx有深入的了解才能了解方法的不兼容性。如果您真的想要这样的东西,请查看redux-cycles它使用cycle.js并主要具有这些目标。我发现它需要太多的仪式来满足我的口味,但是如果您感兴趣,我建议您旋转一下。

正如ThorbenA所提到的,我毫不避讳地承认redux-saga目前(16/13/16)是redux复杂副作用管理的明确领导者。它是较早开始的,拥有更强大的社区。因此,将事实标准用于新来的孩子有很多吸引力。我认为可以肯定地说,如果您在没有先验知识的情况下使用这两种方法,那将会有些混乱。我们俩都使用相当高级的概念,一旦您“了解”,复杂的副作用管理就容易多了,但是直到那时,仍然有很多绊脚石。

我能提供的最重要的建议是不要在需要它们之前引入任何一个这些库。如果您仅进行简单的ajax调用,则可能不需要它们。redux-thunk愚蠢易学,并且提供了足够的基础知识-但是异步越复杂,redux-thunk就会变得越难(甚至不可能)。但是对于redux-observable / saga而言,它在异步方面越复杂,它的作用就越多。在同一项目中将redux-thunk与其他一个(redux-observable / saga)一起使用也有很多优点!将redux-thunk用于您的普通简单内容,然后仅将redux-observable / saga用于复杂的内容。这是保持生产力的好方法,因此您不必为redux-observable / saga争夺那些与redux-thunk无关紧要的东西。


3
刚看完您的讲话(uuhf声音!),然后立即按⌘+ T +“ redux-saga vs redux-observable”。我已经使用redux-saga很长时间了(尤其是在React Native中),但是看完您的演讲和这篇文章后,我可以看到redux-obs的一些用例(对我而言)。实际上会更合适。您关于debounceTime()并失去了对一种非常通用的逻辑的控制的例子对我来说非常有用。感谢您的解释。
Hulvej'5

3
刚才也看到了谈话,并做了更多的谷歌搜索。好东西@jayphelps,谢谢分享。我特别喜欢您关于将redux-thunk与redux-observable / saga结合使用的评论。这很有意义,为什么在不必要时使简单的AJAX请求过于复杂。话虽这么说,但为了保持一致和保持人们的一致,有话要说。再次感谢!
Spets

在升级到redux-saga / redux-observable之前,您可以尝试redux-dispatch-listener,它非常简单,已经可以解决您的一些用例:github.com/slorber/redux-dispatch-subscribe
Sebastien Lorber

这是一个非常有用的答案。谢谢!我喜欢能够将RxJS的知识转移到其他领域/框架的观点。
安塞兰

@jayphelps这将是“复杂异步”的示例。目前,我正在尝试评估项目是否应该从重击更改为“传奇/可观察”。谢谢:)
山姆·博凯

64

我认为您需要考虑一些事项。

  1. 复杂
  2. 编码风格
  3. 学习曲线
  4. 可测性

假设我们要从API获取用户

// Redux-Saga

import axios from 'axios' 

function* watchSaga(){
  yield takeEvery('fetch_user', fetchUser) // waiting for action (fetch_user)
}

function* fetchUser(action){
    try {
        yield put({type:'fetch_user_ing'})
        const response = yield call(axios.get,'/api/users/1')
        yield put({type:'fetch_user_done',user:response.data})
  } catch (error) {
        yield put({type:'fetch_user_error',error})
  }
}

// Redux-Observable
import axios from 'axios'

const fetchUserEpic = action$ => 
    action$
        .ofType('fetch_user')
        .flatMap(()=>
          Observable.from(axios.get('/api/users/1')) // or use Observable.ajax
            .map(response=>({type:'fetch_user_done', user:response.data}))
            .catch(error => Observable.of({type:'fetch_user_error',error}))
            .startWith({type:'fetch_user_ing'})
        )

另外,我写这篇文章是为了比较Redux-saga和Redux-Observable之间的差异。在此处演示文稿中查看此链接


3
通过链接进行的这种并排比较很棒,谢谢
rofrol

1
我喜欢这种比较,但是我想提出一个问题。当您使用api调用比较它们时-您将fetch用于可观察到的Redux。凉。但是,当您显示“可取消”差异时..您不使用提取-而是使用内部的Observable.ajax ...为什么呢?我宁愿使用“提取”或“ axios”将其保留。否则,那里的工作很棒。
james emanon

5
@jamesemanon我认为他没有使用fetch,因为fetch API还没有取消的选项。(有关此内容的更多信息:github.com/whatwg/fetch/issues/27
Daniel Andrei

哇,与所有示例进行深入比较是最好的。谢谢!
RadekMatěj'19

22

我在Redux-Saga上使用Redux-Observable,因为相对于生成器,它更喜欢使用Observable。我将它与RXJS一起使用,它是一个功能强大的库,用于处理数据流。可以将其视为lodash进行异步处理。关于任何缺点,选择方面的陷阱和折衷,请看一下Jay Phelps的回答

redux-saga作为一个项目存在的时间比redux-observable更长,因此这肯定是主要卖点。您会发现更多文档,示例,并且可能拥有更好的社区来获得支持。

与此相反的是,您在redux-saga中学习的运算符和API几乎不像在各处使用RxJS那样可移植。redux-observable在内部是超级超级超级简单,实际上只是为您提供了一种自然的方式来使用RxJS。因此,如果您了解RxJS(或想要了解),那是非常自然的选择。

目前,我对大多数人的建议是,如果您不得不问应该使用哪一个,则可能应该选择redux-saga。


9

Redux-Observable是一个了不起的库,我们在生产环境中使用它已有1.5年之久,到目前为止没有任何问题,它可以完美测试,并且可以轻松地与任何框架集成。我们的并行套接字通道极度过载,唯一使我们免于冻结的是Redux-Observable

我想在这里提三点。

1.复杂性和学习曲线

Redux传奇轻松击败了redux-observable。如果您只需要一个简单的请求就可以完成授权,并且由于某些原因而不想使用redux-thunk,则应该考虑使用redux-saga,它更容易理解。

如果您不具备Observable的先验知识,那将是您的痛苦,您的团队将为您提供培训:)

2. Observable和RxJS能为我提供什么?

当涉及到异步逻辑时,Observable是您的瑞士刀,实际上,Observable可以为您做几乎所有的事情。您永远不要将它们与功能强大得多的Promise或Generator进行比较,就像将Optimus Prime与Chevrolet进行比较一样。

那RxJS呢?它就像lodash.js,但是对于异步逻辑,一旦您进入就永远不会切换到其他东西。

3.反应性扩展

只需检查此链接

http://reactivex.io/languages.html

对所有现代编程语言都实现了响应式扩展,这只是您进行函数式编程的关键。

因此,花点时间明智地学习RxJS并使用redux-observable :)


7

我重视Rx跨语言和运行时的可移植性。即使您的应用程序不会更改语言,您的职业生涯也可能会改变。在学习中获得最大的影响,但是您可以自己调整大小。特别是通往.Net LINQ的绝佳门户。


2
明智的选择,尽管生成器也与语言无关。
Greg Herbowicz

3

既然这里有很多关于redux的演讲,我以为我会提出异议。我不使用redux-observable或RxJS,因此无法进行并行比较,但是我使用sagas效果很好。

对于它的价值,我在Web应用程序的生产中使用了Sagas。

萨加斯vs.汤克

佐贺胜出。我不喜欢笨拙的动作创作者如何运用逻辑。连续进行一些请求也很麻烦。我短暂地看了看这个工作可以观察到的redux,但是选择了Sagas。

Sagas的学习曲线

了解什么是发电机以及为什么它们很重要是了解萨加斯的关键。但是我要强调的是,您不需要内外都知道生成器。您只需要知道您正在使用yield语句传递控制权,并且在您的异步代码解析后,传奇故事就会传递回控制权。在此之后,不难理解传奇中发生了什么。

核心的传奇方法是(以我的经验):

  • call-调用任何代码并获取返回值。支持承诺。异步处理和Sagas之间的巨大协同作用。
  • select-呼叫选择器。这一点非常出色。选择器是redux的核心,并且100%支持!
  • put-又名dispatch动作。实际上,您可以分派任意数量的物品!

还有其他功能,但是如果您能熟练掌握这三个功能,那么您将处于真正的优势。

结论

我选择sagas的原因是易于使用。redux-observable看起来像一个挑战。我对Sagas感到100%满意。比我预期的还要快乐。

以我的经验,萨加斯人比笨拙的人更好,并且相对容易理解。Rx并不是每个人的茶。如果您不是来自该生态系统和/或将来不打算使用Rx,我将强烈认为sagas而不是redux-observable。


2

如果你写的打字稿您的应用程序,我建议你检查无类型。它受Redux-Observable的启发,也依赖于RxJS,但是有用于构建应用程序的整个生态系统。

redux-observable / redux-saga的最大缺点是缺乏指导原则。没有关于如何减少负载减少器,saga或史诗的官方指南。扩展更大的应用程序时,代码拆分至关重要。延迟加载的自定义解决方案通常无法与HMR一起使用,从而导致不良的开发人员体验。

无类型的优点:

  1. 专为TypeScript设计的
    所有API均针对Typescript和类型安全性而设计:
    • 打字稿可以提高您的工作效率,但不会减慢您的工作速度。
    • 仅需要必要的注释:状态,动作参数。
    • 没有类型转换。一切都是自动推断的。95%的代码看起来像纯JavaScript。
    • 没有RootAction,RootEpic,RootState或其他帮助程序类型。
  2. 提供所有构件
    • 无类型包括构建中型或企业级应用程序的所有内容。
    • 您无需依赖多个小型库。
  3. 模块化
    • 适当的模块化对于构建可扩展的应用程序至关重要。
    • 无需为史诗,化简,类型等创建根文件。创建新模块后,可以从任何位置附加它。与标准React组件类似。
  4. 自以为是
    • 默认情况下,所有常见用例和问题均已解决。无需过多考虑如何解决琐碎的问题。
    • 提供了所有建议和最佳实践!

查看https://typeless.js.org/


1
在推荐您主要负责的软件时,应添加免责声明。
Hagelt18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.