Занятие 8.

RxJS и функциональное программирование  

SIS.Angular.2018

Кернер Денис

 

План занятия

Что такое RxJS

Для чего оно нужно

О функциональном программировании

Примеры

О RxJS

Примеры

Итоги

 

 

Reactive extensions for JS

Библиотека для работы с событиями и потоками данных

Интенсивно используется в Angular

 

 

  • Event emitter
  • HTTP
  • Async pipe
  • Router
  • Reactive Forms

 

 

Давайте изучать?

Есть маленький нюанс..

Кривая изучения RxJS без попытки понять основы функционального программирования.

Функциональное программирование (ФП)

ФП (лямбда исчисление) - программирование на основе функций.

// левая часть - определение функции
// правая часть - выражение которое ее вычисляет
// = означает что левую часть можно заменять правой,
// в выражениях использующих эту функцию
f(x) = y

f(x) = 2 * x
f(x) = x * x
// и т.д.

Основные свойства ФП:

  • Чистые функции
  • Функции как объекты первого рода
  • Функции высших порядков
  • Иммутабельность
  • Замыкания
  • Ссылочная прозрачность (левую часть можно заменить правой)

 

Применяя эти свойства, мы получаем:

  • Декларативность
  • Тестируемость
  • Более красивый код
  • Возможность комбинировать функции между собой, решая огромное количество задач, малыми средствами
  • Рекурсия!

Недостатки ФП:

  • Выше уровень абстракции
  • Выше порог вхождения
  • Сложность с обучающим материалом – много материала, пытающегося сразу нагрузить математикой, без практики

Что же делать? Больше практики!

  • Отсортировать список
  • Убрать записи по условию
  • Сконвертировать записи (из объекта в число)
  • Вычислить минимальное/среднее значение

Еще больше практики!

  • Делаем плоский массив из вложенного
function concatAll(array) {
  function concatAllAcc(element, accumulator) {
    if (!Array.isArray(element)) {
      accumulator.push(element);
    } else {
      if (element.length > 0) {
        concatAllAcc(element[0], accumulator);
        concatAllAcc(element.slice(1), accumulator);
      }
    }
  }
  let res = [];
  concatAllAcc(array, res);
  return res;
}

Итоги:

Несмотря на всю академичность, ФП вполне успешно применяется в продакшне:

  • Твиттер написан на Scala (backend)
  • Росработа написана на Scala (backend)
  • Ericsson применял Erlang в своих телекоммуникационных проектах

 

Подходы из ФП активно проникают и в другие языки,

например лямбды и потоки в java 8

 

Что почитать:

Проблема: Обработка событий на колбэках сложна и чревата ошибками. Callback hell
 

Частичное решение: Промисы
 

Полное решение: RxJS

Reactive extensions for JavaScript

Голливудский принцип:

 

 

 

Есть два вида работы с коллекциями - когда мы сами запрашиваем значения (pull), и когда мы подписываемся на получение новых значений (push).

Push коллекции

  • pull - итераторы
  • push - observables
  • Observable
  • Observer next *(error|complete)?

  • Subscription
  • Operators
  • Subject multicast

Основные элементы:

Observable = Iterable * Observer

Пример создания Observable

var observable = new Observable(function (observer) {
  observer.next(1);
  observer.next(2);
  setTimeout(() => {
    observer.next(3);
    observer.complete();
  }, 1000);
});

console.log('just before subscribe');
observable.subscribe({
  next: x => console.log('got value ' + x),
  error: err => console.error('error occurred: ' + err),
  complete: () => console.log('done'),
});
console.log('just after subscribe');
just before subscribe
got value 1
got value 2
just after subscribe
got value 3
done

 Важность subscribe

Пока не будет подписки через метод subscribe  - мы не получим никаких значений.

Это еще называется cold observables

В чем мощь наблюдаемых объектов?

В операторах и их сочетаниях с помощью pipe

Типы операторов:

  • Создания - from, fromPromise
  • Преобразования - map
  • Фильтрации - filter
  • Комбинирования - combineLatest, merge
  • Обработки ошибок - retry, catchError
  • Агрегации - reduce, scan

Marble diagrams для изучения RxJS

Marble diagrams = диаграммы c шариками

Временная ось. слева направо

Значения что посылает Observable

Успешное

завершение

Пунктир показывает трансформацию значений исходного Observable. Прямоугольник показывает

оператор

Новый Observable - результат оператора

Ошибка трансформации, не умеем переворачивать круги

Примеры операторов: filter, map

Диаграмма комбинирования Observables

Последовательное применение операторов.

Как применить последовательно? Pipe.

import { map, switchMap, throttle } from 'rxjs/operators';

myObservable
  .pipe(map(data => data * 2), switchMap(...), throttle(...))
  .subscribe(...);

Практика

 

Пример: автокомплит

const { fromEvent } = Rx;
const { map, throttleTime, filter } = RxOperators;

fromEvent(document, 'mousemove').pipe(
  map(event => event.clientX),
  filter(x => x > 300),
  throttleTime(300)
)
const searchBox = document.getElementById('search-box');
const typeahead = fromEvent(searchBox, 'input').pipe(
  map((e: KeyboardEvent) => e.target.value),
  filter(text => text.length > 2),
  debounceTime(10),
  distinctUntilChanged(),
  switchMap(() => ajax('/api/endpoint'))
);

typeahead.subscribe(data => {
 // Handle the data from the API
});

Пример: реагируем на клики только в правой части экрана

Что посмотреть/почитать

Домашнее задание

Тренируемся с rxJs:

Применяем операторы:

  • pipe
  • debounceTime
  • debounce
  • timer
  • interval
  • fromEvent

Спасибо за внимание!

Вопросы?

Занятие 8

By Сибирские интеграционные системы