In Angular, if there is an Ajax call, the default changes from a Promise to an Observable. Let’s take a look:

// Promise
this.httpClient.get('/users/xxxx').toPromise().then(user => this.user = user);
Copy the code

It’s easy to draw an analogy to an Observable’s scheme:

// Promise
this.httpClient.get('/users/xxxx').subscribe(user => this.user = user);
Copy the code

Because we can think of promises as observables that emit values only once. In fact, by simple comparison, then is completely different from subscribe,

this.httpClient.get('/users/xxxx').toPromise().then
Copy the code

Come closer to:

this.httpClient.get('/users/xxxx').subscribe
Copy the code

So a bigger difference between promises and observables is that promises are automatically subscribe and unsubscribe observables.

So you see, when we replace promises with Observables, the question we have to think about is, when do we unsubscribe?

In general, an Observable used in a front-end framework unsubscribe when the Component is destroyed to prevent memory leaks. Such as Angular’s ngDestroy. It’s not hard to think of the simplest and most straightforward solution:

this.subscriptions = []; this.subscriptions.push( this.httpClient.get('/users/xxxx').subscribe(); ) ; / /... / /... ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); }Copy the code

The problem with this is also obvious. Each time we subscribe, we somehow wrap a layer around it, which increases the code complexity. Of course, you can also define a local variable, which also adds some duplicate code.

So, is there a very elegant way? In fact, there is no such thing as a compromise. We can reduce the number of packages for push. Github.com/wardbell/su…

Through subsink, our only benefit is that we can reduce a layer of code wrapping, which is a relatively elegant and compromise solution.

export class SomeComponent implements OnDestroy { private subs = new SubSink(); . this.subs.sink = observable$.subscribe(...) ; this.subs.sink = observable$.subscribe(...) ; this.subs.sink = observable$.subscribe(...) ; . // Unsubscribe when the component dies ngOnDestroy() { this.subs.unsubscribe(); }}Copy the code

Not only does unsubscribe take a lot of time and effort, but it is also a hassle to subscribe. Angular provides async pipe to eliminate the problem of unsubscribe and unsubscribe relatively easily. However, async can be cumbersome to use when there is a lot of stream data in component, as described in the previous two articles.

Async essentially automatically helps you to unsubscribe when a Component is destroyed, simplifying the process and code.

In fact, from the nature of the problem, the Observer could have been unsubscribed if we had effectively prevented the component from being destroyed. RxJS has a set of take operators that limit observables to a range.

this.destroy$ = new Subject(); this.httpClient.get('/users/xxxx').takeUntil(this.destroy$).subscribe(); / /... / /... ngOnDestroy() { this.destroy$.next(true); }Copy the code

Of course, the downside of this approach is obvious: Destroy $is inherently uncontrollable by the framework, and users can emit value anywhere else, causing unknowable problems.

TakeUntil (this.destroy$) essentially waits for the Angular layer to encapsulate the Life Cycle function, or to be able to customize the Component class to prevent users from manually modifying destroy$at the logical layer.