No, it is not bad practice to use .subscribe() within components as long you unsubscribe from those observables when components are destroyed (i.e. within the ngOnDestroy() method). The async pipe automatically unsubscribes from its observable which is why it is the recommended approach.
If you do not unsubscribe from your observables when your components are destroyed, you will end up with "memory leaks", or rather objects that won't be garbage collected because there still exists a reference to them. You might also see strange behavior because there are phantom subscriptions still out there. Components will be destroyed at times such as when navigating to different routes if you're using the router or when child components within an *ngFor are refreshed.
For my projects, I make myself an abstract parent class for components that handles the unsubscribing for me.
import { OnDestroy } from '@angular/core';
import { Subscriber, Subscription } from 'rxjs/Rx';
/**
* Class `BaseComponent` encapsulates common logic for components such as providing
* a mechanism to automatically unsubscribe from Rx subscriptions upon destruction.
*/
export abstract class BaseComponent implements OnDestroy {
protected _subscriptions: { [key: string]: Subscriber<any>|Subscription> } = {};
protected get subscriptions() {
return this._subscriptions;
}
constructor() {}
ngOnDestroy() {
for (let name in this.subscriptions) { // tslint:disable-line:prefer-const
if (this.subscriptions.hasOwnProperty(name)) {
const subscription = this.subscriptions[name];
if (subscription.unsubscribe) {
subscription.unsubscribe();
this.subscriptions[name] = null;
} else {
console.warn(`Property '${name}' on 'subscriptions' was not unsubscribed.`);
}
}
}
}
}
Then in your components you simply have to save any subscriptions into the subscriptions object with an arbitrary but unique name.
@Component({ /* ... */ })
export class MyComponent extends BaseComponent {
constructor() {
super();
this.subscriptions['thisNameIsArbitrary'] =
Observable.interval(1000)
.subscribe();
}
}