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

我用过Redux-Saga 。 到目前为止,用它编写的代码很容易理解,除了JS生成器函数不时搞乱我的头。 根据我的理解, Redux-Observable可以实现处理副作用但不使用生成器函数的类似工作。

但是,Redux-Observable的文档并没有提供很多关于为什么它比Redux-Saga更好的观点。 我想知道是否使用生成器函数是使用Redux-Observable的唯一好处。 而使用Redux-Observable而不是Redux-Saga会有什么不好的地方呢? 提前致谢。

免责声明:我是可重复观察的作者之一,所以我很难100%公正。

我们目前没有提供任何可以观察到的原因,比可能的更好,因为…事实并非如此。 😆

tl; dr对两者都有利弊。 许多人会发现一个比另一个更直观,但如果你不知道RxJS(redux-observable)或生成器/“作为数据的效果”(redux-saga),那么两者都会以不同的方式学习。

他们以极其相似的方式解决同样的问题,但是有一些基本的差异,只有在足够的时候才能真正显现出来。

可观察到的几乎将所有东西都推迟到惯用的RxJS。 所以,如果你有RxJS的知识(或获得它),学习和使用可观察到的是超级超自然的。 这也意味着这个知识可以转化为除了redux之外的东西。 如果您决定切换到MobX,如果您决定切换到Angular2,如果您决定切换到未来的热点X,RxJS可以帮助您。 这是因为RxJS是一个通用的asynchronous库,在很多方面就像是一种编程语言 – 整个“Reactive Programming”范式。 RxJS自2012年以来一直存在,并开始作为Rx.NET的一个端口(几乎所有主要语言都有“端口”,这很有用 )。

redux-saga本身就提供了基于时间的运营商,所以虽然你在过程pipe理者风格上获得的有关生成器和处理副作用的知识是可以转让的,但是实际的运营商和使用情况并没有被其他主要的图书馆所使用。 所以这有点不幸,但肯定不应该是一个破坏自己的事情。

它也使用“效果作为数据”( 在这里描述 ),这可能很难把头部包裹起来,但这意味着你的简历代码本身并不会实际执行副作用。 相反,您使用的助手函数创build对象,就像代表意图做副作用的任务,然后内部库为您执行。 这使得testing非常容易,不需要嘲笑,对一些人来说非常有吸引力。 但是,我个人发现这意味着你的unit testing会重新实现你的传奇逻辑的大部分 – 使这些testing不是非常有用的海事组织(这个意见是不是每个人都共享)

人们经常问我们为什么不用那种可以观察到的东西来做这样的事情:对我来说,它与正常的惯用Rx基本上是不相容的。 在Rx中,我们使用如.debounceTime()这样的运算符来封装去抖动所需的逻辑,但是这意味着如果我们想要创build一个并不实际执行去抖动的版本,而是用意图发出任务对象,现在已经失去了Rx的力量,因为你不能再链接操作员,因为他们会操作这个任务对象,而不是操作的真正结果。 这是很难解释优雅。 这又需要对Rx有深入的了解,以了解方法的不兼容性。 如果你真的想要这样的东西,检查使用cycle.js的redux周期 ,主要有这些目标。 我觉得这需要太多的仪式来满足我的口味,但是我鼓励你在感兴趣的时候给它一个旋转。

正如ThorbenA所说的,我毫不回避地承认redux-saga目前是(16/13/16)在复杂的副作用pipe理方面的领先者。 它起步较早,社区较为健壮。 所以对于使用事实上的标准对块上的新孩子有很大的吸引力。 我认为可以肯定地说,如果你在没有事先知识的情况下使用,你会感到困惑。 我们都使用相当先进的概念,一旦你“得到”,使复杂的副作用pipe理变得更容易,但在此之前,很多人都绊倒了。

我能给的最重要的build议不是在你需要这些库之前带上这两个库。 如果你只做简单的ajax调用,你可能不需要它们。 redux-thunk是愚蠢的简单学习,并提供足够的基础知识 – 但asynchronous越复杂越难(或甚至不可能)它成为redux thunk。 但是在许多方面对于可观测/传奇来说,它最明显的异化是更复杂的。 在同一个项目中使用redux-thunk还有很多优点(redux-observable / saga)! 为你的常见简单的东西,然后只使用redux-observable /传奇复杂的东西。 这是一个保持高效的好方法,所以你不会为了减less繁琐的事情而对付可观察/传奇的事情。

我认为有些事情需要考虑。

  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之间的差异,我写了这篇文章。 看看这个链接或演示文稿 。

我在Redux-Saga上使用Redux-Observable,因为宁愿使用observer来处理发生器。 我使用它与RXJS,这是一个强大的数据库工作库。 把它想象为asynchronous的lodash。 从任何一个缺点来看,在select一个方面的问题和妥协方面,请看Jay Phelps的这个答案 :

作为一个项目已经存在的时间比可观测的还要长,所以这肯定是一个重要的卖点。 你会发现更多的文档,例子,并可能有一个更好的社区获得支持。

相反的是,你所学习的操作者和APIs并不像学习RxJS那样被使用, redux-observable是超级超级简单的内部,它只是给你一个自然的方式让你使用RxJS。 所以如果你知道RxJS(或者想要),这是一个非常自然的契合。

我现在对大多数人的build议是,如果你必须问你应该使用哪一个,那么你可能应该select一个简化版。

我重视Rx所具有的语言和运行时间的可转换性。 即使你的应用程序不会改变语言,你的职业生涯也许会。 获得最佳的学习能力,但是你要为自己做好准备。 这对于.NET LINQ来说是一个非常棒的入口。