Зачем использовать Redux-Observable поверх Redux-Saga?


133

Я использовал Redux-Saga . Код, написанный с его помощью, до сих пор легко рассуждать, за исключением того, что функция генератора JS время от времени ломает мне голову. Насколько я понимаю, Redux-Observable может выполнить аналогичную работу, которая обрабатывает побочные эффекты, но без использования функции генератора.

Тем не менее, документы из Redux-Observable не дают много мнений о том, почему он превосходит Redux-Saga. Я хотел бы знать, не является ли использование функции генератора единственным преимуществом использования Redux-Observable. И какие могут быть недостатки, ошибки или компромиссы при использовании Redux-Observable вместо Redux-Saga? Заранее спасибо.


Я сделал забавный, но подробный блог, в котором Redux-Saga превосходит Redux-Observable для людей, которые не живут / не едят / не дышат наблюдаемыми в течение всего дня. Я уверен, что это здорово, если весь ваш стек можно наблюдать. shift.infinite.red/…
Гант Лаборде

Ответы:


236

Отказ от ответственности: я являюсь одним из авторов наблюдаемых по редуксу, поэтому мне трудно быть беспристрастным на 100%.

В настоящее время мы не приводим причин, по которым наблюдаемая редукс лучше, чем сага о редуксе, потому что ... это не так. 😆

TL; DR есть плюсы и минусы для обоих. Многие найдут одно более интуитивно понятным, чем другое, но оба сложны в изучении по-разному, если вы не знаете RxJS (наблюдаемый при редуксе) или генераторы / «эффекты как данные» (избыточная сага).

Они решают одну и ту же проблему чрезвычайно похожими способами, но имеют некоторые фундаментальные различия, которые становятся действительно очевидными только после того, как вы их достаточно используете.

Наблюдаемый за редуксом откладывает почти все до идиоматического RxJS. Таким образом, если у вас есть знания RxJS (или вы получили их), изучение и использование наблюдаемых в редуксе суперъестественно. Это также означает, что эти знания могут быть переданы другим вещам. Если вы решите переключиться на MobX, если вы решите переключиться на Angular2, если вы решите переключиться на какую-то будущую популярность X, очень велики шансы, что RxJS может вам помочь. Это связано с тем, что RxJS - это универсальная асинхронная библиотека, которая во многом похожа на язык программирования сама по себе - целую парадигму «реактивного программирования». RxJS существует с 2012 года и начинался как порт Rx.NET («порты» есть почти на всех основных языках, это очень полезно ).

redux-saga предоставляет свои операторы, основанные на времени, так что, хотя знания, которые вы приобретаете о генераторах и обработке побочных эффектов в этом стиле менеджера процессов, можно передавать, фактические операторы и их использование не используются ни в одной другой основной библиотеке. Так что это немного прискорбно, но, конечно, само по себе не должно нарушать договоренности.

Он также использует «эффекты как данные» ( описанные здесь ), которые поначалу может быть трудно обернуть вокруг, но это означает, что ваш код излишней саги фактически не выполняет сами побочные эффекты. Вместо этого, вспомогательные функции, которые вы используете, создают объекты, которые похожи на задачи, представляющие намерение выполнить побочный эффект, а затем внутренняя библиотека выполняет это за вас. Это делает тестирование чрезвычайно простым, не требующим насмешек и очень привлекательным для некоторых людей. Тем не менее, я лично нашел, что это означает, что ваши юнит-тесты переопределяют большую часть логики вашей саги - делая эти тесты не очень полезными IMO (это мнение разделяют не все)

Люди часто спрашивают, почему мы не делаем что-то подобное с помощью redux-observable: для меня это принципиально несовместимо с обычным идиоматическим Rx. В Rx мы используем такие операторы, .debounceTime()которые инкапсулируют логику, необходимую для устранения неполадок, но это означает, что если бы мы хотели создать его версию, которая на самом деле не выполняет устранение неполадок и вместо этого генерирует объекты задачи с намерением, вы теперь потеряли мощь Rx, потому что вы больше не можете просто связывать операторы, потому что они будут работать с этим объектом задачи, а не с реальным результатом операции. Это действительно сложно объяснить элегантно. Это снова требует глубокого понимания Rx, чтобы понять несовместимость подходов. Если вам действительно нужно что-то подобное, посмотрите redux-циклыкоторый использует cycle.js и в основном преследует эти цели. Я считаю, что это требует слишком много церемоний, на мой вкус, но я рекомендую вам попробовать, если это вас интересует.

Как упоминал ThorbenA, я не уклоняюсь от признания, что redux-saga в настоящее время (13.10.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
Просто посмотрел ваш доклад (ухф звук!) И сразу же нажал ⌘ + T + «redux-saga vs redux-observable». Я уже довольно давно использую redux-saga (особенно в React Native), но после просмотра вашего выступления и этого поста я могу увидеть некоторые варианты использования (для меня), когда redux-obs. на самом деле было бы лучше. Ваш пример о debounceTime()"потере" контроля над очень общей логикой произвел на меня впечатление. Спасибо за объяснение.
Hulvej

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 другим доменам / фреймворкам.
Anselan 05

@jayphelps Что было бы примером "сложной асинхронности". В настоящее время я пытаюсь оценить, следует ли мне переключиться с thunk на saga / observables для проекта. Спасибо :)
Сэм Бокай

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. прохладный. НО, когда вы показываете "отменяемые" различия ... вы НЕ используете fetch - вместо этого вы используете внутренний Observable.ajax ... почему? Я бы предпочел использовать "выборку" или "аксиомы". в остальном там отличная работа.
Джеймс Эманон

5
@jamesemanon Я предполагаю, что он не использует fetch, потому что у fetch API еще нет возможности отменить. (подробнее об этом: github.com/whatwg/fetch/issues/27 )
Даниэль Андрей,

Вау, это подробное сравнение со всеми примерами - лучшее. Спасибо!
Radek Matěj

22

Я использую Redux-Observable вместо Redux-Saga, потому что предпочитаю работать с наблюдаемыми, а не с генераторами. Я использую его с RXJS, мощной библиотекой для работы с потоками данных. Думайте об этом как о lodash для async. Что касается недостатков, ошибок и компромиссов при выборе одного из вариантов, взгляните на этот ответ Джея Фелпса:

redux-saga как проект существует дольше, чем redux-observable, так что это, безусловно, один из основных аргументов в пользу продажи. Вы найдете больше документации, примеров и, вероятно, у вас будет лучшее сообщество, от которого можно получить поддержку.

Счетчик в том, что операторы и API, которые вы изучаете в redux-saga, не так легко переносимы, как изучение RxJS, которое используется повсеместно. redux-observable - это супер-супер-супер-простой внутри, он действительно просто дает вам естественный способ использования RxJS. Так что, если вы знаете RxJS (или хотите знать), это очень естественно.

Мой совет на данный момент для большинства людей заключается в том, что если вам нужно спросить, какой из них вам следует использовать, вам, вероятно, следует выбрать redux-saga.


9

Redux-Observable - потрясающая библиотека, мы используем ее в продакшене уже 1,5 года без каких-либо проблем, она отлично тестируется и может быть легко интегрирована с любым фреймворком. У нас сильно перегружены параллельные каналы сокетов, и единственное, что спасает нас от зависаний, - это Redux-Observable.

У меня есть 3 момента, которые я хотел бы здесь упомянуть.

1. Сложность и кривая обучения

Redux-saga легко превосходит redux-observable здесь. Если вам нужен только простой запрос для выполнения авторизации, и вы по каким-то причинам не хотите использовать redux-thunk, вам следует подумать об использовании redux-saga, это просто легче понять.

Если у вас нет предварительных знаний о Observable, вам будет больно, и ваша команда обучит вас :)

2. Что мне могут предложить Observable и RxJS?

Когда дело доходит до асинхронной логики, Observable - ваш швейцарский нож, Observable может буквально все делать за вас. Никогда не сравнивайте их с обещаниями или генераторами, он намного мощнее, это то же самое, что сравнивать Оптимус Прайм с Шевроле.

А что с RxJS? Это похоже на lodash.js, но для асинхронной логики, как только вы войдете, вы никогда не переключитесь на что-то другое.

3. Реактивное расширение

Просто проверьте эту ссылку

http://reactivex.io/languages.html

Реактивное расширение реализовано для всех современных языков программирования, это просто ваш ключ к функциональному программированию.

Так что потратьте свое время с умом на изучение RxJS и используйте redux-observable :)


7

Я ценю переносимость между языками и средами выполнения, которые есть у Rx. Даже если ваше приложение не меняет языки, ваша карьера может. Получите максимальную отдачу от своего обучения, как бы вы это ни оценили. В частности, это отличный выход в .Net LINQ.


2
Разумный выбор, хотя генераторы тоже не зависят от языка.
Грег Хербович

3

Поскольку здесь ведется целая куча разговоров, наблюдаемых за редукцией, я подумал, что приведу аргумент в саге. Я не использую redux-observable или RxJS, поэтому я не могу дать параллельное сравнение, но я использовал саги с большим эффектом.

Как бы то ни было, я использую саги в производстве в веб-приложении.

Саги против Thunk

Сага безоговорочно побеждает. Мне не понравилось, как thunk вложил логику в моих создателей действий. Это также затрудняло выполнение нескольких запросов подряд. Я вкратце посмотрел на redux-observable для этой работы, но остановился на Sagas.

Кривая обучения сагам

Понимание того, что такое генераторы и почему они важны, является ключом к пониманию саг. Но подчеркну, что генераторы знать не нужно. Вам нужно только знать, что вы передаете управление с помощью оператора yield, и что сага вернет управление после разрешения вашего асинхронного кода. После этого не очень сложно понять, что происходит в саге.

Основные методы саги (по моему опыту):

  • call- Вызвать любой бит кода и получить возвращаемое значение. Поддерживает обещания. Отличная синергия между асинхронной обработкой и сагами.
  • select- Вызов селектора. Этот бит довольно гениальный. Селекторы являются ядром redux, и они поддерживаются на 100%!
  • put- ака dispatchдействие. Фактически отправляйте столько, сколько хотите!

Есть и другие функции, но если вы овладеете этими тремя, вы окажетесь в действительно хорошем состоянии.

Вывод

Причина, по которой я выбрал саги, заключалась в простоте использования. redux-observable выглядел как проблема. Сагами доволен на 100%. Счастливее, чем я ожидал.

По моему опыту, саги (намного) лучше, чем переходы, и их относительно легко понять. Rx - чашка чая не для всех. Я бы настоятельно рассмотрел саги, а не наблюдаемые редукции, если вы не из этой экосистемы и / или не планируете использовать Rx в будущем.


2

Если вы пишете свое приложение на Typescript, я рекомендую выбрать вариант без типа . Он вдохновлен Redux-Observable, а также зависит от RxJS, но существует целая экосистема для создания приложения.

Самым большим недостатком саги о сокращении и саге о сокращении является отсутствие руководящих принципов. Нет никаких официальных инструкций по ленивым редукторам нагрузки, сагам или эпосам. Разделение кода имеет решающее значение при масштабировании больших приложений. Индивидуальные решения для отложенной загрузки обычно не работают с HMR, что ухудшает опыт разработчиков.

Бестиповые плюсы:

  1. Разработано для TypeScript
    Все API-интерфейсы предназначены для машинописного текста и обеспечения безопасности типов:
    • Машинопись повысит вашу продуктивность, а не замедлит.
    • Требуются только необходимые аннотации: состояние, аргументы действия.
    • Без приведения типов. Все делается автоматически. 95% кода выглядит как чистый javascript.
    • Нет RootAction, RootEpic, RootState или других вспомогательных типов.
  2. Обеспечьте все строительные блоки
    • Typeless включает все необходимое для создания приложений среднего или корпоративного уровня.
    • Вам не нужно полагаться на несколько небольших библиотек.
  3. модульность
    • Правильная модульность имеет решающее значение для создания масштабируемых приложений.
    • Нет необходимости создавать корневые файлы для эпиков, редукторов, типов и т. Д. Создав новый модуль, вы можете прикрепить его из любого места. Аналогичен стандартным компонентам React.
  4. упрямый
    • Все распространенные варианты использования и проблемы решаются по умолчанию. Не нужно долго думать, как исправить тривиальные проблемы.
    • Предоставляются все рекомендации и лучшие практики!

Посетите https://typeless.js.org/


1
Вы должны добавить отказ от ответственности, рекомендуя программное обеспечение, для которого вы являетесь основным разработчиком.
Hagelt18,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.