BACK
Lessons3. The lifecycle: next, error, complete
Lessons · 03

3. The lifecycle: next, error, complete

The signals an Observable can send

Every Observable "talks" to its subscriber through three kinds of notification. They're worth memorizing, because together they describe the whole lifecycle of a stream — from the first value to the very end.

  • next(value) — "here's the next value." It can fire many times: 0, 1, 5, millions.
  • error(err) — "something went wrong, I won't send anything more." This is a terminal signal: after it, the stream is dead.
  • complete() — "that's it, I'm finished, no more values." Also terminal, but without an error.

The stream contract

Formally it's written as next* (error | complete)?. Read it as: "any number of nexts in a row, then maybe either an error or a complete (not both, and never more than once)."

In other words, error and completion are mutually exclusive. Once one happens, the stream is closed for good — calling next afterward is pointless.

The object form of subscribe

In earlier lessons we passed subscribe a plain function — that's the callback for next. But when you also want to handle the error and the completion, pass an object with three keys: { next, error, complete }. Each one is optional.

Your task

  1. Inside the recipe function, loop over the data array. A for (const item of data) { ... } works well.
  2. For each element, check: if it equals the string 'error', call subscriber.error('Error!') and immediately return (to leave the function — there's nothing to do after an error).
  3. If it's a normal element, send it with subscriber.next(item).
  4. After the loop (if no error occurred), call subscriber.complete().

Expected log order: Next: Apple → Next: Banana → Error: Error!. After the error, Cherry and Complete never show up — the stream is dead.

Solution 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
Hit Run to see the result...