[Fixed] Do I have to explicitly define an observable as "finite"?

Issue

There are several resources out there (like this one) that define what a "finite" observable is (an observable that eventually stops emitting values). From what I’ve read, it is generally accepted that finite observables do not need to be unsubscribed from.

Is there anything that needs to be done to explicitly define an Observable as "finite"? This article shows how the Angular HttpClient calls complete() on its Observer is something that forces its observers to unsubscribe. Is this what makes it "finite"? Or can an observable be finite just by its nature, without explicitly calling complete()? If so, is it safe to NOT unsubscribe from an observable that is finite by nature?

Solution

Yes and No.

Some observables are finite by construction. This includes all Promises, for example. It also includes

const someArray = [/* array contents */]
from(someArray).subscribe({
  next: console.log, // Log emissions
  error: _ => {},    // We could ignore errorsby omitting this line, but hey
  complete: () => console.log("This observable completed");
});

After the contents of the array are logged, this observable will complete. By construction.

Here’s a simplified version of from that doesn’t complete

function endlessFrom(array) {
  return new Observable(observer => {
    array.forEach(observer.next.bind(observer))
    // observer.complete(); <- Oh no! ;)
    return {
      unsubscribe: () => {} // Do nothing
    }
  })
}

const someArray = [/* array contents */]
endlessFrom(someArray).subscribe({
  next: console.log, // Log emissions
  error: _ => {},    // We could ignore errorsby omitting this line, but hey
  complete: () => console.log("This observable completed");
});

If you run this, you’ll see that "This observable completed" is never logged. Always, a finite observable will call its observer’s complete or error callback explicitly. There are no observables that complete via any library magic of any sort.

That being said, many operators do that work for you. RxJS#from constructs Promises and Arrays are finite, but you can make any source finite with (for example) take, takeWhile, ect.


But Really: No

There’s no runtime flag or property that can make an observable finite. The only way is for that Observable to emit an error or complete. This makes sense. Even if you could tag an observable as being finite, what mechanism could an observer use to know when an observable had fulfilled its obligation to complete?

Leave a Reply

(*) Required, Your email will not be published