Dans les applications web sans framework, la gestion de l'asynchrone se fait généralement avec trois outils :
les callbacks : des fonctions appelées lorsque l'événement attendu a lieu ;
les Promise : des objets avec des méthodes
then()
etcatch()
qui sont appelées lorsque l'événement attendu a lieu ;les fonctions async/await : des fonctions qui mettent leur exécution en attente jusqu'à l'arrivée de l'événement attendu.
Angular, étant un framework très complet, nous fournit un nouvel outil pour gérer des événements qui ont lieu au cours du temps : la library RxJS et ses Observables.
Soyez observateur
Le principe de base est très simple :
Un Observable est un objet qui émet des valeurs au cours du temps.
Il est typé : il émettra toujours des valeurs du même type.
Un Observable peut émettre une erreur : à ce moment-là, l'Observable est détruit et n'émettra plus de valeurs.
L'Observable peut également être complété : il est aussi détruit et n'émettra plus rien.
Comme son nom l'indique, on peut observer un Observable et réagir à ses émissions – c'est d'ailleurs tout l'intérêt ! On observe un Observable avec sa méthode subscribe()
pour "souscrire" à l'Observable.
Comme toujours, les concepts de programmation sont plus faciles à comprendre quand on les pratique, donc pratiquons !
Créez et souscrivez à un Observable
Le premier Observable que vous allez créer va émettre des nombres croissants toutes les secondes.
import { Component, OnInit } from '@angular/core';
import { interval } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
ngOnInit() {
const interval$ = interval(1000);
}
}
Ici, vous utilisez la méthode interval()
(importée depuis rxjs
) pour créer un Observable qui émet des nombres croissants, en passant le nombre de millisecondes qui doit séparer les émissions. Vous stockez cet Observable dans une constante nommée interval$
.
Vous allez utiliser une approche très simple pour souscrire à cet Observable (qui sera à proscrire par la suite, mais vous verrez bien !). On peut passer un callback à la méthode subscribe()
qui sera exécuté à chaque émission, donc vous pouvez faire ceci :
interval$.subscribe(value => console.log(value));
Si vous ouvrez votre navigateur à la racine de l'application et que vous ouvrez la console, vous verrez les émissions de cet Observable :
Toutes les secondes, l'Observable émet un nombre. Ce nombre est ensuite capté et traité par la méthode passée à subscribe()
.
Il est important de noter que si on ne souscrit pas à un Observable, dans l'énorme majorité des cas, il n'émet rien. Par exemple, attendons 3 secondes avant de souscrire à interval$
. Remplacez la souscription actuelle avec :
setTimeout(() => {
interval$.subscribe(value => console.log(value));
}, 3000);
Si vous regardez maintenant la console, vous verrez le même résultat qu'avant, sauf qu'il commence au bout de 3 secondes.
Pour une dernière expérience importante, mélangeons les deux exemples précédents :
interval$.subscribe(value => console.log(value));
setTimeout(() => {
interval$.subscribe(value => console.log(value));
}, 3000);
Voici le résultat :
On voit qu'il y a donc deux instances de l'Observable. Il est très important de se rendre compte que le comportement par défaut d'un Observable est de créer une nouvelle instance pour chaque souscription.
Affichez les émissions avec le pipe async
Très souvent, l'objectif sera d'afficher les émissions d'un Observable dans le DOM, et pour cela, Angular nous fournit le pipe async
. Contrairement à tous les autres pipes que vous avez rencontrés jusqu'ici, le pipe async
ne formate pas des données : il souscrit à un Observable et insère les émissions dans le DOM.
Commençons par modifier légèrement la structure de AppComponent :
import { Component, OnInit } from '@angular/core';
import { interval, Observable } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
interval$!: Observable<number>;
ngOnInit() {
this.interval$ = interval(1000);
}
}
Maintenant que AppComponent contient un membre, on peut utiliser le pipe async
pour l'afficher dans le template. Dans app.component.html
:
<!--<app-header></app-header>-->
<!--<router-outlet></router-outlet>-->
{{ interval$ | async }}
Dans le DOM, vous voyez maintenant les nombres qui augmentent :
Certes cet exemple est très simple et n'est pas très utile, mais le concept de souscrire à un Observable, que ce soit avec la méthode subscribe()
ou le pipe async
, est très important – vous vous en servirez très, très souvent.
En résumé
Les Observables émettent des valeurs au cours du temps ;
La méthode
interval()
permet de générer un Observable qui émet des nombres croissants ;La méthode
subscribe()
permet de souscrire à un Observable dans le code TypeScript ;Le pipe
async
souscrit à un Observable pour afficher ses émissions dans le template.
Dans le prochain chapitre, vous allez commencer à apprendre comment manipuler les émissions des Observables avec les opérateurs. C'est parti !