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 }. Любой из них необязателен.
Что нужно сделать
- Внутри функции-рецепта пройдитесь циклом по массиву
data. Подойдётfor (const item of data) { ... }. - Для каждого элемента проверьте: если он равен строке
'error'— вызовитеsubscriber.error('Error!')и сразу жеreturn(чтобы выйти из функции — после ошибки делать нечего). - Если элемент обычный — отправьте его через
subscriber.next(item). - После цикла (если ошибка не случилась) вызовите
subscriber.complete().
Ожидаемый порядок логов: Next: Apple → Next: Banana → Error: Error!. После ошибки Cherry и Complete уже не появятся — поток мёртв.
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')
});