RxJS Tip: Understand the Terminology: Observer
Tags: angular, rxjs
Published: 2020-11-16 21:41:59

We've discussed [Observable](https://dev.to/angular/rxjs-tip-understand-the-terminology-observable-52ph) and [Subscription](https://dev.to/angular/rxjs-tip-understand-the-terminology-subscription-4j03). Another key RxJS concept is **Observer**.

# What Is an Observer?
An Observer watches for emissions and notifications from an Observable after a consumer subscribes to that Observable.

An Observer defines an interface with callback functions for each type of Observable notification: next, error, and complete.

Use the **next** callback to process the emitted item.
Use the **error** callback to implement exception handling.
Use the **complete** callback to perform cleanup when the Observable is complete. (This is not used often in an Angular application.)

#How Do You Define an Observer?
There are several ways to define an Observer.

### Explicitly (Uncommon)
Though not common, you can define an Observer explicitly by creating an object with three callback functions: next, error, and complete. 

```typescript
// Define an explicit observer (uncommon)
const observer = {
  next: apple => console.log(`Apple was emitted ${apple}`),
  error: err => console.log(`Error occurred: ${err}`),
  complete: () => console.log(`No more apples, go home`)
};
```

The **next** method argument is the emitted item. The arrow function specifies what to do with that item. In this case, we are simply logging it to the console.

The **error** method argument is the error emitted when an error occurs. The arrow function specifies what to do with the error notification. In this case, we are logging the error to the console.

The **complete** method has no argument. The arrow function defines what to do when the Observable is complete. In this case, it logs a message to the console.

We then pass that Observer object into the Observable subscribe method to react to the Observable's emissions and notifications.

```typescript
// Pass the Observer into the subscribe (uncommon)
const sub = source$.subscribe(observer);
```

### Pass a Single Callback
It is more common to pass the Observer callback functions directly into the Observable subscribe method.

You can only pass one object to the subscribe method.

If you only need the next callback, pass it directly as the subscribe argument.

```typescript
// Pass the next callback function directly
const sub = source$.subscribe(
   apple => console.log(`Apple was emitted ${apple}`)
);
```

### Pass an Observer Object
Since you can only pass one object to subscribe, if you need to handle multiple types of notifications, pass an Observer object with the desired set of callbacks.

```typescript
// Pass an Observer object with callback arrow functions
const sub = source$.subscribe({
  next: apple => console.log(`Apple was emitted ${apple}`),
  error: err => console.log(`Error occurred: ${err}`),
  complete: () => console.log(`No more apples, go home`)
});
```

Notice that the above code passes an object into the subscribe method with next, error, and complete methods. You only need to specify the methods for the notifications you'll handle. So if you don't need to process the complete notification, you don't need to specify it.

### What if You Don't Want to Use Arrow Functions?
The prior examples all used arrow functions, denoted with `=>`. Some developers may prefer to use declared named functions instead of arrow functions when defining Observer callbacks. Like this:

```typescript
const sub = source$.subscribe({
  next(apple) { console.log(`Apple was emitted ${apple}`) },
  error(err) { console.log(`Error occurred: ${err}`)},
  complete() { console.log(`No more apples, go home`)}
});
```

Notice the syntax difference. Here we define each function (next) with it's parameter (apple) and function body denoted with {}.

But watch out for `this`. In TypeScript (and in JavaScript), `this` is scoped to the function. So if you have code like the following:

```typescript
// Watch out for `this`
const sub = source$.subscribe({
  next(apple) { this.apple = apple }, // Does NOT reference the 
                                      // class-level variable
  error(err) { console.log(`Error occurred: ${err}`)},
  complete() { console.log(`No more apples, go home`)}
});
```

It may not work as expected. The `this.apple` will *not* reference a class-level variable and will instead define a function-scoped variable.

#How Do the Pieces Fit Together?
The Observable, Observer, and Subscription work together to:
* Tell the Observable to start emissions/notifications
* Provide callback functions to react to those emissions/notifications
* Set up a subscription that allows for unsubscribing

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qper84x94v6gqpige6cv.jpg)

Here are the concepts shown on a more formal marble diagram.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/abne9lv8iggsfpumd55z.jpg)

Thanks to @Michael_Hladky for this marble diagram.

Here is a more common example usage in an Angular application.

**Service**
```typescript
  products$ = this.http.get<Product[]>(this.productsUrl)
    .pipe(
      tap(data => console.log(JSON.stringify(data))),
      catchError(this.handleError)
    );
```
In the above code, products$ represents the Observable.

>It is a common practice to add a `$` suffix to a variable that represents an Observable. This makes it easier to see when the code is working with an Observable.

**Component**
```typescript
ngOnInit(): void {
  this.sub = this.productService.products$.subscribe({
      next: products => this.products = products,
      error: err => this.errorMessage = err
    });
}
```
In the component, the Observer object is passed into the subscribe method, defining two callbacks: next and error.

The `this.sub` represents the Subscription returned from the subscribe method. This is used to unsubscribe on ngOnDestroy.

I hope that clarified the meaning of the term **Observer** and demonstrates how three key RxJS concepts: Observable, Subscription, and Observer work together.