Explanation of AsyncPipe in Angular

Let's get started
The AsyncPipe is one of Angular’s most powerful built-in features. Async pipe has been designed to work with Observable and Promise data sources to handle the delayed data in templates. It simplifies subscription management, prevents memory leaks, and enhances code readability.
What is the AsyncPipe?
AsyncPipe is a one of the built-in Angular pipe which automatically subscribes to an Observable or Promise and returns the latest emitted value. It also unsubscribe when the component is destroyed to handle memory leaks. Here we need to be carefull, if our component will stay more, we should take care the unsubscription.
{{ observableOrPromiseDataVariable | async }}
Here observableOrPromiseDataVariable is providing the data with the help of the Observable or Promise. And we use async pipe to handle the data.
Why to Use the AsyncPipe?
If we don't need to process the Observable data source, it is easier to use it in smaller parts. Due to its design is to subscribe and unsubscribe automatically. So, some dummy components we dont need to handle the unsubscription also if not necessary.
export class MyComponent implements OnInit, OnDestroy {
data!: any;
private subscription!: Subscription;
ngOnInit(): void {
this.subscription = this.myService.getData().subscribe(res => {
this.data = res;
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
Here we will call the api and make the subscription, Assign the data to a variable and at the destruction, handle the unsubscription.
<div *ngIf="myService.getData() | async as data">
{{ data }}
</div>
With async pipe, it will automatically fetch the data and show it in the related place and unsubscribe it when the comppnent destroyed.
Using AsyncPipe with Observable
Let's improve our examples and see how we can use the async pipe with an Observable in a real world example:
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>('https://jsonplaceholder.typicode.com/users');
}
}
This service will fetch a online mock user list from the given url.
@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html'
})
export class UserListComponent {
users$ = this.userService.getUsers(); // Observable<User[]>
constructor(private userService: UserService) {}
}
This component has the declared Observable variable which is assigned the api call to fetch the users from the service.
<ul>
<li *ngFor="let user of users$ | async">
{{ user.name }} - {{ user.email }}
</li>
</ul>
Async pipe here is waiting for the Observable emits the data, and when the data is there then handle the rendering. ALso it handles the unsubscription automatically.
Using AsyncPipe with Promise
Above we have made an example with Observable. We can also use the async with Promise. Let's make an example with Promise as well
@Component({
selector: 'app-promise-example',
template: `
<div *ngIf="promiseData | async as data; else loading">
{{ data }}
</div>
<ng-template #loading>Loading...</ng-template>
`
})
export class PromiseExampleComponent {
promiseData: Promise<string>;
constructor() {
this.promiseData = new Promise(resolve =>
setTimeout(() => resolve('Data loaded from promise!'), 2000)
);
}
}
Above you can see in the constructor we have fetched the data and assigned to the variable direclty. In template side it will be handled automatically by async pipe.
Common Pitfalls
Testing Components with AsyncPipe
To test the async in the components, we need to use fakeAsync and inside the function we need to use the tick function. tick makes the function is to wait until the observables emits the value
Below you can see a test example
it('should render user name', fakeAsync(() => {
const fixture = TestBed.createComponent(UserListComponent);
fixture.detectChanges();
tick(); // wait until observable emits
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('Leanne Graham');
}));
Conclusion
Async pipe is one of the fundamental built-in util of Angular. It makes asynchoronous data handling simplier and reducing the boiler plate. The nature of async pipe is to proceed declerative and avoiding manual subsciption and unsubscription. If you’re dealing with data in Observables or Promises in Angular, using effectively AsyncPipe is a really important. Use it and you will see your templates become cleaner and more reactive.That is all.
Happy asynchoronous data handling.
Burak Hamdi TUFAN