Подтвердить что ты не робот

Как Observables (Rx.js) сравниваются с генераторами ES2015?

Насколько я понимаю, ниже приведены методы решения рабочих процессов асинхронного программирования:

  • Обратные вызовы (CSP)
  • Promises

Новые подходы:

  • Rx.js Наблюдаемые (или mostjs, bacon.js, xstream и т.д.)
  • Генераторы ES6
  • Асинхронный /Await

Теперь мы переходим от обратных вызовов и promises к этим более новым подходам. В настоящее время я понимаю: Async/Await больше похожа на более чистую абстракцию поверх генераторов ES2015.

То, что я не могу понять, - это концептуальная разница между Observables и Generators. Я использовал и широко, и не испытывал никаких проблем с их использованием.

Что меня смущает, это пример использования Observables и Generators. Я пришел к выводу, что, в конце концов, они решают одну и ту же проблему - асинхронность. Только потенциальная разница, которую я вижу, - это генераторы, которые по сути обеспечивают императивную семантику кода, а Observables с использованием Rxjs, по-видимому, обеспечивают реактивную парадигму. Но так ли это?

Должны ли быть критерии выбора между Observable и Generator? Каковы плюсы и минусы.

Не хватает ли большой картины?

Также с Observable, в конечном счете, создающим в будущем Ecmascript, есть promises (с отменным маркером)/Наблюдаемые/Генераторы собираются конкурировать друг с другом?

4b9b3361

Ответ 1

Наблюдаемые изменения push, и, следовательно, контролируемая, а не функция, реагирующая на нее, находится под контролем. Генераторы, с другой стороны, требуют вытащить из них значения. Таким образом, функция, которая будет реагировать на новое значение, определяет, когда она готова к новому значению.

У меня были проблемы с противодавлением с помощью наблюдаемых, но с генераторами вы можете позволять значениям так медленно, как вы хотите.

Изменить: последний вопрос. Promises являются только наблюдаемыми, которые только излучают один раз, поэтому я не думаю, что они будут соревноваться друг с другом. Я думаю, что настоящая битва будет асинхронной/ожидающей против наблюдаемых, а async/await имеет начало и уже находится в С# (а теперь Node.js). Но наблюдаемые имеют ощущение сладкой FRP, и функциональная программирование супер крута, поэтому я думаю, что они оба получат хороший кусок mindshare.

Edit2: André Staltz, автор Cycle.js и xstream, и автор Rx.js, написал замечательную статью о том, как связаны генераторы и наблюдатели (в 2018-01-31). В частности, он показывает, как они оба наследуются от общего базового класса.

И теперь потребитель может быть Слушателем ( "наблюдателем" ) или Пуллером, его до потребителя, будет ли он вытаскивать производителя или нет. И производитель может быть Listenable ( "наблюдаемый" ) или "Pullable" ( "iterable" ), вплоть до производителя, если он отправляет данные проактивно или только по требованию. Как вы можете видеть, и потребитель, и производитель - простые функции одного типа:

(num, полезная нагрузка) = > void

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

Я рекомендую прочитать его [ссылка]. В статье представлена ​​ " Callbags", спецификация для обратных вызовов, используемых для реактивного и итеративного программирования. Он реализует эту спецификацию, чтобы сделать крошечную библиотеку для итеративного и реактивного программирования. Чтобы побудить вас прочитать статью и проверить библиотеку, вот несколько примеров из библиотеки 7kb на основе спецификации, которую он представляет:

Пример реактивного программирования

Выберите первые 5 нечетных чисел из часов, которые тикают каждую секунду, затем начните их наблюдать:

const {forEach, interval, map, filter, take, pipe} = require('callbag-basics');

pipe(
  interval(1000),
  map(x => x + 1),
  filter(x => x % 2),
  take(5),
  forEach(x => console.log(x))
);

// 1
// 3
// 5
// 7
// 9

Итерируемый пример программирования

Из диапазона чисел выберите 5 из них и разделите их на 4, затем начните вытягивать их по одному:

const {forEach, fromIter, take, map, pipe} = require('callbag-basics');

function* range(from, to) {
  let i = from;
  while (i <= to) {
    yield i;
    i++;
  }
}

pipe(
  fromIter(range(40, 99)), // 40, 41, 42, 43, 44, 45, 46, ...
  take(5), // 40, 41, 42, 43, 44
  map(x => x / 4), // 10, 10.25, 10.5, 10.75, 11
  forEach(x => console.log(x))
);

// 10
// 10.25
// 10.5
// 10.75
// 11

Ответ 2

Вы можете рассматривать наблюдаемые rxjs как асинхронные генераторы, т.е. генераторы, дающие promises. Просто потому, что контент не гарантированно будет готов в то время, когда мы вызываем .next(в отличие от обычных генераторов)

  • Абонент будет постоянно потреблять в бесконечном цикле содержимое генераторов (вызов .next)
  • Подождите, пока возвращаемое обещание будет разрешено (или отменено), чтобы сделать то, что вы хотите.
  • Наблюдаемый (с асинхронным генератором) будет завершен на выходе генераторов.

Подробнее чтение

предложение асинхронных итераторов