BACK
Уроки3. Жизненный цикл: next, error, complete
Уроки · 03

3. Жизненный цикл: next, error, complete

Какие сигналы умеет посылать Observable

Каждый Observable «общается» с подписчиком через три типа уведомлений. Их полезно запомнить, потому что они описывают весь жизненный цикл потока — от первого значения до завершения.

  • next(value) — «вот тебе очередное значение». Может вызываться много раз: 0, 1, 5, миллионы раз.
  • error(err) — «случилась ошибка, я больше ничего не пришлю». Это терминальный сигнал: после него поток мёртв.
  • complete() — «всё, я закончил, новых значений не будет». Тоже терминальный сигнал, но без ошибки.

Контракт потока

Формально это записывается как next* (error | complete)?. Читается так: «сколько угодно next подряд, а потом, возможно, либо error, либо complete (но не оба, и не больше одного раза)».

Иначе говоря: ошибка и завершение — взаимоисключающие. Произошло одно — поток закрыт навсегда. Дальше вызывать next бессмысленно.

Объектная форма subscribe

В предыдущих уроках мы передавали в subscribe просто функцию — это коллбэк для next. Но если нужно обработать ещё и ошибку, и завершение, передаём объект с тремя ключами: { next, error, complete }. Любой из них необязателен.

Что нужно сделать

  1. Внутри функции-рецепта пройдитесь циклом по массиву data. Подойдёт for (const item of data) { ... }.
  2. Для каждого элемента проверьте: если он равен строке 'error' — вызовите subscriber.error('Error!') и сразу же return (чтобы выйти из функции — после ошибки делать нечего).
  3. Если элемент обычный — отправьте его через subscriber.next(item).
  4. После цикла (если ошибка не случилась) вызовите subscriber.complete().

Ожидаемый порядок логов: Next: Apple → Next: Banana → Error: Error!. После ошибки Cherry и Complete уже не появятся — поток мёртв.

Решение spoiler · click to reveal
const { Observable } = Rx;

const data = ['Apple', 'Banana', 'error', 'Cherry'];

const stream$ = new Observable(subscriber => {
  for (const item of data) {
    if (item === 'error') {
      subscriber.error('Error!');
      return;
    }

    subscriber.next(item);
  }

  subscriber.complete();
});

stream$.subscribe({
  next: value => console.log('Next: ' + value),
  error: error => console.log('Error: ' + error),
  complete: () => console.log('Complete')
});
script.ts // TypeScript
CONSOLE · Console Output
Нажмите на запуск, чтобы увидеть результат...