1810 votes

Quelle est la différence entre les Promesses et les Observables?

Quelle est la différence entre Promise et Observable dans Angular ?

Un exemple sur chacun serait utile pour comprendre les deux cas. Dans quel scénario pouvons-nous utiliser chaque cas ?

32 votes

Je vous suggérerais de lire ce post; Promesse Angular2 vs observable

7 votes

5 votes

À toute personne lisant cette question-réponse - en tant que personne impliquée dans les deux mondes en tant que mainteneur, conférencier et utilisateur de longue date, je vous encourage à lire la documentation officielle de RxJS et la documentation MDN sur les promesses. Je trouve personnellement que les réponses fournies ici sont entièrement trompeuses et incorrectes et je pense qu'elles sont, bien qu'émanant de personnes essayant d'aider, très nocives.

1991voto

Günter Zöchbauer Points 21340

Promesse

Une Promesse gère un événement unique lorsqu'une opération asynchrone est terminée ou échoue.

Remarque : Il existe des bibliothèques de Promesse qui prennent en charge l'annulation, mais l'ES6 Promesse ne le fait pas pour le moment.

Observable

Un Observable est comme un Stream (dans de nombreuses langues) et permet de transmettre zéro ou plusieurs événements où le rappel est appelé pour chaque événement.

Il est souvent préférable d'utiliser un Observable plutôt qu'une Promesse car il offre les fonctionnalités de la Promesse et bien plus encore. Avec un Observable, cela n'a pas d'importance si vous souhaitez gérer 0, 1 ou plusieurs événements. Vous pouvez utiliser la même API dans chaque cas.

Observable a également l'avantage par rapport à la Promesse d'être annulable. Si le résultat d'une requête HTTP vers un serveur ou toute autre opération asynchrone coûteuse n'est plus nécessaire, l'Abonnement d'un Observable permet d'annuler l'abonnement, tandis qu'une Promesse appellera finalement le rappel de réussite ou d'échec même lorsque vous n'avez plus besoin de la notification ou du résultat qu'elle fournit.

Alors qu'une Promesse démarre immédiatement, un Observable ne démarre que si vous vous y abonnez. C'est pourquoi les Observables sont appelés paresseux.

L'Observable fournit des opérateurs comme map, forEach, reduce, ... similaire à un tableau

Il existe également de puissants opérateurs comme retry(), ou replay(), ... qui sont souvent très pratiques. Une liste d'opérateurs fournis avec rxjs

L'exécution paresseuse permet de construire une chaîne d'opérateurs avant que l'observable ne soit exécuté par abonnement, pour réaliser une programmation plus déclarative.

227 votes

Alors, y a-t-il une bonne raison d'utiliser Promise au lieu d'Observable dans le cas d'un seul rappel, ou bien les Observables devraient-ils également être utilisés puisqu'ils peuvent fonctionner de cette manière ? En gros, est-il bon de pratiquer le "Observable all the things" ou Promise a-t-il toujours sa place ?

94 votes

Si vous voulez utiliser le style réactif, il vous suffit d'utiliser des observables partout. Si vous avez uniquement des observables, vous pouvez facilement les composer. Si vous les mélangez, ce n'est plus aussi propre. Si le style réactif ne vous importe pas, vous pouvez utiliser des promesses pour des événements ponctuels où vous ne vous souciez pas de l'annulation et des observables pour des flux d'événements.

2 votes

Pour une bonne ressource d'introduction sur Observables/RxJs/Programmation Réactive : gist.github.com/staltz/868e7e9bc2a7b8c1f754 ("L'introduction à la Programmation Réactive que vous avez manquée")

410voto

trungk18 Points 12923

Les deux sites Promises et Observables nous fournissent des abstractions qui nous aident à faire face aux asynchrone la nature de nos applications. La différence entre les deux a été clairement soulignée par @Günter et @Relu.

Puisqu'un extrait de code vaut mille mots, examinons l'exemple ci-dessous pour mieux les comprendre.

Merci @Christoph Burgdorf pour l'incroyable article


Angular utilise les Observables de Rx.js au lieu des promesses pour traiter le HTTP.

Supposons que vous construisiez un fonction de recherche qui devrait vous montrer instantanément les résultats au fur et à mesure que vous tapez. Cela vous semble familier, mais cette tâche comporte de nombreux défis.

  • Nous ne voulons pas frapper le point de terminaison du serveur chaque fois que l'utilisateur appuie sur une touche, il devrait l'inonder d'une tempête de HTTP demandes. En fait, nous ne voulons l'activer qu'une fois que l'utilisateur a arrêté de taper au lieu de le faire à chaque frappe.
  • Ne frappez pas le point final de la recherche avec l'option paramètres de la même requête pour les demandes ultérieures.
  • Traiter les réponses non ordonnées. Lorsque nous avons plusieurs demandes en cours de traitement en même temps, nous devons tenir compte des cas où elles reviennent dans un ordre inattendu. Imaginons que nous tapions d'abord ordinateur Stop, une demande sort, nous tapons. voiture , stop, une demande sort. Maintenant nous avons deux requêtes en vol. Malheureusement, la requête qui transporte les résultats de ordinateur revient après la requête qui porte les résultats pour voiture .

La démo sera simplement constituée de deux fichiers : app.ts et wikipedia-service.ts . Dans un scénario réel, il est plus que probable que l'on divise davantage les choses, cependant.


Vous trouverez ci-dessous Basé sur des promesses qui ne gère aucun des cas limites décrits.

wikipedia-service.ts

import { Injectable } from '@angular/core';
import { URLSearchParams, Jsonp } from '@angular/http';

@Injectable()
export class WikipediaService {
  constructor(private jsonp: Jsonp) {}

  search (term: string) {
    var search = new URLSearchParams()
    search.set('action', 'opensearch');
    search.set('search', term);
    search.set('format', 'json');
    return this.jsonp
                .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search })
                .toPromise()
                .then((response) => response.json()[1]);
  }
}

Nous injectons le Jsonp pour faire un GET contre le API Wikipedia avec un terme de recherche donné. Notez que nous appelons toPromise afin de passer d'un Observable<Response> à un Promise<Response> . Vous finissez par vous retrouver avec un Promise<Array<string>> comme type de retour de notre méthode de recherche.

app.ts

// check the plnkr for the full list of imports
import {...} from '...';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Wikipedia Search</h2>
      <input #term type="text" (keyup)="search(term.value)">
      <ul>
        <li *ngFor="let item of items">{{item}}</li>
      </ul>
    </div>
  `
})
export class AppComponent {
  items: Array<string>;

  constructor(private wikipediaService: WikipediaService) {}

  search(term) {
    this.wikipediaService.search(term)
                         .then(items => this.items = items);
  }
}

Pas vraiment de surprise ici non plus. Nous injectons notre WikipediaService et exposer sa fonctionnalité via une méthode de recherche dans le modèle. Le modèle se lie simplement à keyup et appelle search(term.value) .

Nous déballons le résultat de la Promesse que la méthode de recherche du WikipediaService renvoie et de l'exposer comme un simple tableau de chaînes de caractères au modèle de sorte que nous puissions avoir *ngFor le parcourir en boucle et nous faire une liste.

Voir l'exemple de Basé sur des promesses la mise en œuvre sur Plunker


Observables briller vraiment

Modifions notre code pour que le point de terminaison ne soit pas sollicité à chaque frappe, mais qu'il n'envoie une requête que lorsque l'utilisateur a cessé de taper pendant deux secondes. 400 ms

Pour dévoiler de tels super pouvoirs, nous devons d'abord obtenir un Observable<string> qui porte le terme de recherche que l'utilisateur a tapé. Plutôt que de se lier manuellement à l'événement keyup, nous pouvons tirer parti de la fonction d'Angular formControl directive. Pour utiliser cette directive, nous devons tout d'abord importer la directive ReactiveFormsModule dans notre module d'application.

app.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { JsonpModule } from '@angular/http';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [BrowserModule, JsonpModule, ReactiveFormsModule]
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

Une fois importé, nous pouvons utiliser formControl dans notre modèle et lui attribuer le nom "term".

<input type="text" [formControl]="term"/>

Dans notre composant, nous créons une instance de FormControl de @angular/form et l'exposer comme un champ sous le nom de terme sur notre composant.

Dans les coulisses, terme expose automatiquement un Observable<string> comme propriété valueChanges à laquelle nous pouvons nous abonner. Maintenant que nous avons un Observable<string> pour surmonter l'entrée de l'utilisateur, il suffit d'appeler debounceTime(400) sur notre Observable . Cela renverra un nouveau Observable<string> qui n'émettra une nouvelle valeur que s'il n'y a pas eu de nouvelles valeurs pendant 400 ms.

export class App {
  items: Array<string>;
  term = new FormControl();
  constructor(private wikipediaService: WikipediaService) {
    this.term.valueChanges
              .debounceTime(400)        // wait for 400ms pause in events
              .distinctUntilChanged()   // ignore if next search term is same as previous
              .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));
  }
}

Ce serait un gaspillage de ressources que d'envoyer une autre demande pour un terme de recherche dont notre application affiche déjà les résultats. Tout ce que nous avons à faire pour obtenir le comportement souhaité est d'appeler la commande distinctUntilChanged juste après avoir appelé debounceTime(400)

Voir l'exemple de Observable la mise en œuvre sur Plunker

Pour traiter les réponses non ordonnées, veuillez consulter l'article complet. http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

Dans la mesure où j'utilise Http dans Angular, je suis d'accord pour dire que dans les cas d'utilisation normaux, il n'y a pas beaucoup de différence entre Observable et Promise. Aucun des avantages n'est vraiment pertinent ici en pratique. J'espère que je pourrai voir des cas d'utilisation avancés à l'avenir :)


En savoir plus

48 votes

Je ne suis pas entièrement convaincu par la décision de transformer le service Http en Observable. Chaque explication que j'entends repose sur le même exemple : la recherche par terme. Mais cela concerne la gestion des événements du navigateur. J'aimerais savoir quel avantage il y a à l'appliquer lors du traitement des requêtes http asynchrones.

1 votes

La décision était-elle accidentelle pour éviter les schémas mixtes ?

6 votes

@AlexPollan, il y a en fait une bonne explication des avantages du service http renvoyant un observable sur ce podcast avec Ben Lesh: devchat.tv/js-jabber/…. En fin de compte, le principal avantage est que vous pouvez annuler un observable, et un cas d'utilisation pour cela est décrit dans le lien ci-dessus - bien que un peu artificiel - est que si vous appelez plusieurs apis et ne vous intéressez qu'à la première réponse, peu importe lequel des api vous avez appelé vous répond en premier, vous pouvez ensuite annuler les demandes aux autres.

316voto

Alireza Points 40192

À la fois les Promesses et les Observables nous aideront à travailler avec les fonctionnalités asynchrones en JavaScript. Ils sont très similaires dans de nombreux cas, cependant, il existe encore quelques différences entre les deux, les promesses sont des valeurs qui se résoudront de manière asynchrone comme les appels HTTP. D'autre part, les observables traitent une séquence d'événements asynchrones. Les principales différences entre eux sont répertoriées ci-dessous :

Promesse :

  • ayant un pipeline
  • habituellement uniquement utilisé avec un retour de données asynchrones
  • pas facile à annuler

Observable :

  • sont annulables
  • sont réessaiables par nature comme retry et retryWhen
  • diffusent des données dans plusieurs pipelines
  • ayant des opérations semblables à des tableaux comme map, filter, etc.
  • peuvent être créés à partir d'autres sources comme les événements
  • ce sont des fonctions, qui pourraient être souscrites ultérieurement

Aussi, j'ai créé l'image graphique pour vous ci-dessous pour montrer les différences visuellement :

Image des Promesses et Observables

5 votes

Promesse "pas facile à annuler" , est-il possible de les annuler ?

17 votes

Oui, il y a aussi un moyen de les annuler... certaines personnes utilisent bluebird ou des bibliothèques tierces... en utilisant la bibliothèque Q dans Angular il y a des moyens de l'annuler... mais comme je l'ai dit pas très pratique

0 votes

Avoir un pipeline a parfois des avantages, par exemple dans APP_INITIALIZER, s'il y a plusieurs pipelines, il arrive parfois qu'il ne puisse jamais se terminer ou se termine plusieurs fois.

116voto

besserwisser Points 420

Il y a un inconvénient des Observables manquant dans les réponses. Les Promises permettent d'utiliser les fonctions async/await ES7. Avec elles, vous pouvez écrire du code asynchrone comme s'il s'agissait d'un appel de fonction synchrone, donc vous n'avez plus besoin de rappels. La seule possibilité pour les Observables de le faire est de les convertir en Promises. Mais lorsque vous les convertissez en Promises, vous ne pouvez avoir qu'une seule valeur de retour à nouveau :

async function getData(){
    const data = await observable.first().toPromise();
    //do stuff with 'data' (no callback function needed)
}

Lire la suite : Comment puis-je `attendre` sur un Rx Observable ?

39 votes

Aussi surpris pourquoi personne n'a souligné cet avantage énorme des Promesses - la simplicité et la transparence grâce à async/await. J'ai basculé vers les Promesses juste pour la possibilité d'écrire un code plat. La logique métier simple et le code d'interaction utilisateur ne devraient pas ressembler à de la science de la fusée et être pollués par l'enfer imbriqué des extensions réactives. De plus, async/await n'est pas seulement pour l'avenir, vous pouvez l'utiliser dans des applications de production publiques maintenant en utilisant des transpileurs. J'utilise TypeScript 2.3 et c'est génial, comme un vrai langage.

2 votes

Agréable, mais penser de manière réactive et tout avec les RxOperators, peut-être que ce n'est pas une fonctionnalité révolutionnaire.

2 votes

Je utilise Promise async/await tout le temps et c'est vraiment puissant. Il offre une familiarité et une clarté du code tout en utilisant un vrai moteur javascript asynchrone. En revanche, les Observables sont synchrone, ils sont exécutés dans la pile d'exécution principale alors que Promise async/await utilise des fonctionnalités asynchrones en js dans le moteur : boucle d'événements, libuv, file de tâches micro etc. Rendre les Observables asynchrones en utilisant setTimeout() est idiot car cela monopolise les ressources et vous ne pouvez pas contrôler l'ordre d'exécution dans la boucle d'événements. Il utilise la partie WebAPI de la boucle d'événements, tandis que les événements dans la file de tâches micro ont la priorité.

91voto

Aravind Points 21523

Promesses

  1. Définition : Vous aide à exécuter des fonctions de manière asynchrone et à utiliser leurs valeurs de retour (ou exceptions), mais une seule fois lors de l'exécution.
  2. Non paresseux
  3. Non annulable (il existe des bibliothèques de promesses qui prennent en charge l'annulation, mais ce n'est pas le cas de la Promesse ES6 jusqu'à présent). Les deux décisions possibles sont
    • Rejeter
    • Résoudre
  4. Impossible de réessayer (les promesses doivent avoir accès à la fonction d'origine ayant renvoyé la promesse pour avoir une capacité de réessai, ce qui est une mauvaise pratique)

Observables

  1. Définition : Vous aide à exécuter des fonctions de manière asynchrone et à utiliser leurs valeurs de retour dans une séquence continue (plusieurs fois) lors de l'exécution.
  2. Par défaut, c'est paresseux car il émet des valeurs au fur et à mesure que le temps progresse.
  3. Dispose de nombreux opérateurs qui simplifient l'effort de codage.
  4. Un opérateur retry peut être utilisé pour réessayer lorsque nécessaire, et si nous devons réessayer l'observable en fonction de certaines conditions, retryWhen peut être utilisé.

Remarque : Une liste d'opérateurs accompagnée de leurs diagrammes interactifs est disponible ici sur **RxMarbles.com**

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X