Quelqu'un peut-il s'il vous plaît expliquer la différence entre Promise
et Observable
en angulaire?
Un exemple sur chacun serait utile pour comprendre les deux cas ..___ Dans quel scénario pouvons-nous utiliser chaque cas?
Promettre
Promise
gère un événement unique lorsqu'une opération asynchrone se termine ou échoue.
Remarque: Il existe des bibliothèques Promise
qui prennent en charge l'annulation, mais ES6 Promise
ne le fait pas jusqu'à présent.
Observable
Un Observable
est comme unStream
(dans de nombreuses langues) et permet de passer zéro ou plusieurs événements où le rappel est appelé pour chaque événement.
Observable
est souvent préférable à Promise
car il fournit les fonctionnalités de Promise
et plus. Avec Observable
, peu importe si vous voulez gérer 0, 1 ou plusieurs événements. Vous pouvez utiliser la même API dans chaque cas.
Observable
a aussi l'avantage sur Promise
d'être annulable . Si le résultat d'une requête HTTP adressée à un serveur ou d'une opération asynchrone coûteuse n'est plus nécessaire, la variable Subscription
d'une variable Observable
permet d'annuler l'abonnement, alors qu'une variable Promise
appellera éventuellement le rappel réussi ou échoué, même si vous ne le faites pas. besoin de la notification ou du résultat qu'il fournit plus.
Observable fournit opérateurs like map
, forEach
, reduce
, ... semblable à un tableau
Il existe également des opérateurs puissants tels que retry()
ou replay()
, ... qui sont souvent très utiles.
Promises
et Observables
nous fournissent des abstractions qui nous aident à gérer la nature asynchrone de nos applications. La différence entre eux a été clairement soulignée par @ Günter et @Relu.
Étant donné qu’un extrait de code vaut mille mots, examinons l’exemple ci-dessous pour mieux le comprendre.
Merci @Christoph Burgdorf pour le génial article
Angular utilise Rx.js Observables au lieu de promesses de traitement avec HTTP.
Supposons que vous développiez une fonction search qui devrait vous montrer instantanément les résultats en cours de frappe. Cela vous semble familier, mais cette tâche présente de nombreux défis.
HTTP
. Fondamentalement, nous ne voulons appuyer que lorsque l'utilisateur a cessé de taper à la place de chaque frappe.La démo consistera simplement en deux fichiers: app.ts
et wikipedia-service.ts
. Dans un scénario réel, nous diviserions probablement les choses plus haut.
Voici une implémentation Promise-based qui ne gère aucun des cas Edge 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 service Jsonp
pour effectuer une requête GET
contre l'API Wikipedia avec un terme de recherche donné. Notez que nous appelons toPromise
afin de passer d'un Observable<Response>
à un Promise<Response>
. Finalement, finissez 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 une surprise ici non plus. Nous injectons notre WikipediaService
et exposons sa fonctionnalité via une méthode de recherche au modèle. Le modèle se lie simplement à keyup et appelle search(term.value)
.
Nous décompressons le résultat de Promise renvoyé par la méthode de recherche de WikipediaService et l'exposons sous forme de tableau de chaînes au modèle afin que nous puissions avoir *ngFor
le parcourir et créer une liste pour nous.
Voir l'exemple de la mise en œuvre Promise-based sur Plunker
Où Observables brillent vraiment
Modifions notre code pour ne pas marteler le point final à chaque frappe, mais uniquement pour envoyer une demande lorsque l'utilisateur a cessé de taper pendant 400 ms
Pour dévoiler de tels super pouvoirs, nous devons d’abord obtenir un Observable<string>
qui porte le terme de recherche saisi par l’utilisateur. Au lieu de se lier manuellement à l’événement keyup, nous pouvons tirer parti de la directive formControl
de Angular. Pour utiliser cette directive, nous devons d’abord importer la 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 à partir de notre modèle et le définir avec le nom "terme".
<input type="text" [formControl]="term"/>
Dans notre composant, nous créons une instance de FormControl
à partir de @angular/form
et l'exposons sous la forme d'un champ sous le nom de notre composant.
En coulisse, term expose automatiquement un Observable<string>
en tant que propriété valueChanges
auquel nous pouvons nous abonner. Maintenant que nous avons un Observable<string>
, vaincre la saisie de l'utilisateur est aussi simple que d'appeler debounceTime(400)
sur notre Observable
. Cela retournera un nouveau Observable<string>
qui n'émettra une nouvelle valeur que lorsqu'il n'y a pas eu de nouvelle valeur pour 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 d'envoyer une autre demande pour un terme de recherche pour lequel notre application affiche déjà les résultats. Tout ce que nous avons à faire pour obtenir le comportement souhaité est d'appeler l'opérateur distinctUntilChanged
juste après l'appelant debounceTime(400)
Voir l'exemple de la mise en oeuvre de Observable sur Plunker
Pour traiter les réponses erronées, veuillez consulter l’article complet http://blog.iblytram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
En ce qui concerne l’utilisation de Http dans Angular, j’accepte que, dans les cas d’utilisation normale, l’utilisation de Observable over Promise n’est pas très différente. Aucun des avantages n’est vraiment pertinent ici dans la pratique. J'espère que je pourrai voir un cas d'utilisation avancé à l'avenir :)
Apprendre encore plus
Promises et Observables nous aideront à utiliser les fonctionnalités asynchrones en JavaScript. Elles sont très similaires dans de nombreux cas, cependant, il existe encore quelques différences entre les deux. Les promesses sont des valeurs qui résoudront de manière asynchronous
comme les appels http. Par contre, les observables traitent une séquence d'événements asynchrones. Les principales différences entre eux sont énumérés ci-dessous:
promettre:
observable:
Aussi, j'ai créé l'image graphique ci-dessous pour montrer les différences visuellement:
Promesses
Observables
Un opérateur retry peut être utilisé pour réessayer à tout moment, même si nous devons réessayer l'observable en fonction de certaines conditions retryWhen peut être utilisé.
Note: une liste des opérateurs avec leurs diagrammes interactifs est disponible ici à l'adresse RxMarbles.com.
Il manque un aspect des observables dans les réponses. Les promesses permettent d’utiliser les fonctions async/wait de l’ES7. Avec eux, vous pouvez écrire du code asynchrone comme s'il s'agissait d'un appel de fonction synchrone, de sorte que vous n'avez plus besoin de rappels. La seule possibilité pour Observables de le faire est de les convertir en promesses. Mais lorsque vous les convertissez en promesses, vous ne pouvez plus avoir qu'une seule valeur de retour:
async function getData(){
const data = await observable.first().toPromise();
//do stuff with 'data' (no callback function needed)
}
Lectures supplémentaires: Comment puis-je "attendre" sur un observable Rx?
Même si cette réponse est en retard, j'ai résumé les différences ci-dessous,
Observable:
function
qui prend an observer
et renvoie un function Observer: an object with next, error.
subscribe/unsubscribe
dans son flux de données, d'émettre.une valeur suivante pour l'observateur, notify
l'observateur à propos de errors
et Informer l'observateur du stream completion
function to handle next value
, des erreurs et une fin de flux (Événements ui, réponses http, données avec des sockets Web).multiple values
au fil du tempscancel-able/retry-able
et supporte des opérateurs tels que map,filter,reduce
etc.Observable.create()
- renvoie un observable pouvant appeler des méthodes sur -Observer Observable.from()
- convertit un tableau ou une unité itérable en -Observable Observable.fromEvent()
- convertit event into Observable -Observable.fromPromise()
- convertit une promesse en observable -Observable.range()
- renvoie une séquence d'entiers dans la plage spécifiée.Promettre:
Une promesse représente une tâche qui se terminera dans le futur.
Les promesses deviennent resolved by a value
;
Les promesses sont rejetées par des exceptions;
Pas cancellable
et il retourne a single value
Une promesse expose une fonction (then)
-en retourne une nouvelle promise
;
-allows pour la attachment
de celle-ci sera exécutée sur la base de state
;
-handlers
are guaranteed
à exécuter dans order attached
;
Je pense que toutes les autres réponses devraient effacer vos doutes ..__ Néanmoins, je voulais juste ajouter que les observables sont basés sur une programmation fonctionnelle, et je trouve très utile les fonctions qui vont avec, comme map, flatmap, réduire, Zip. La cohérence obtenue par le Web, en particulier lorsque cela dépend des demandes d'API, constitue une amélioration brutale.
Je recommande fortement cette documentation , puisqu'il s'agit de la documentation officielle de reactiveX et que je la trouve la plus claire possible.
Si vous voulez entrer dans observables, je suggérerais ce post en 3 parties: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
Bien que cela soit destiné à RxJava, les concepts sont les mêmes et ils sont très bien expliqués. Dans la documentation de reactiveX, vous avez les équivalences pour chaque fonction. Vous devez chercher RxJS.
Je viens juste de traiter un problème pour lequel Promises était la meilleure solution, et je la partage ici pour tous ceux qui tombent sur cette question au cas où cela serait utile (c'était exactement la réponse que je recherchais plus tôt):
Dans un projet Angular2, j'ai un service qui prend certains paramètres et retourne une liste de valeurs pour remplir les menus déroulants d'un formulaire. Lorsque le composant de formulaire s'initialise, je dois appeler plusieurs fois le même service avec des paramètres différents pour définir un certain nombre de menus déroulants. Toutefois, si je mets simplement en file d'attente toutes les variables pour appeler le service, seule la dernière réussit et l'erreur de repos en dehors. Le service extrait de la base de données ne pouvait traiter qu'une demande à la fois.
Le seul moyen de renseigner avec succès toutes les variables du menu déroulant consiste à appeler le service de manière à empêcher le traitement d'une nouvelle demande jusqu'à la fin de la dernière demande et à ce que le mécanisme Promise/.then résolve le problème.
fetchValueList(listCode): Promise<any> {
return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
.map(response => response.json())
.toPromise();
}
initializeDropDowns() {
this.fetchValueList('First-Val-List')
.then(data => {
this.firstValList = data;
return this.fetchValueList('Second-Val-List')
}).then(data => {
this.secondValList = data;
return this.fetchValueList('Third-Val-List')
}).then(data => {
this.thirdValList = data;
}) }
J'ai défini les fonctions dans le composant, puis appelé initializeDropDowns () dans ngOnInit.
La fonction fetchValueList renvoie une promesse. Le premier appel passe donc le premier listCode et, lorsque la promesse est résolue, la valeur de retour est dans la variable de données du bloc .then, où nous pouvons l'affecter à la variable this.firstValList. Comme la fonction a renvoyé des données, nous savons que le service est terminé et que le second listCode peut être rappelé en toute sécurité. La valeur de retour se trouve dans la variable de données du bloc .then suivant et nous l'affectons à la variable this.secondValList.
Nous pouvons le chaîner autant de fois que nécessaire pour renseigner toutes les variables et, dans le dernier bloc de code, nous omettons simplement l'instruction return et le bloc se termine.
Il s'agit d'un cas d'utilisation très spécifique où nous avons un seul service qui doit être appelé plusieurs fois à l'initialisation du composant et où le service doit terminer son extraction et renvoyer une valeur avant de pouvoir être rappelé, mais dans ce cas, la méthode Promise/.then était idéale.
Promesse - Fournir une valeur future unique. Pas paresseux . Non annulable. Ce sera soit rejeter ou résoudre.
Observable - Fournit une valeur future multiple. Paresseux . Annulable. Il fournit d'autres méthodes en direct carte, filtre, réduit.
Vous pouvez toujours utiliser un observable pour traiter le comportement asynchrone puisqu'un observable a toutes les fonctionnalités qu'une promesse offre (+ extra). Cependant, cette fonctionnalité supplémentaire offerte par Observables n’est parfois pas nécessaire. Il serait alors très onéreux d’importer une bibliothèque pour pouvoir les utiliser.
Utilisez les promesses lorsque vous souhaitez traiter le résultat avec une opération single async. Par exemple:
var promise = new Promise((resolve, reject) => {
// do something once, possibly async
// code inside the Promise constructor callback is getting executed synchronously
if (/* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
//after the promise is resolved or rejected we can call .then or .catch method on it
promise.then((val) => console.log(val)) // logs the resolve argument
.catch((val) => console.log(val)); // logs the reject argument
Ainsi, une promesse exécute du code où elle est résolue ou rejetée. Si la résolution ou le rejet est appelé, la promesse passe d'un état en attente à un état résolu ou rejeté . Lorsque l'état de la promesse est résolu, la méthode then()
est appelée. Lorsque l'état de la promesse est rejeté, la méthode catch()
est appelée.
Utilisez Observables quand il y a un flux (de données) dans le temps que vous devez gérer. Un flux est une séquence d'éléments de données mis à disposition au fil du temps . Des exemples de flux sont:
Dans l'observable lui-même est spécifié lorsque l'événement suivant s'est produit, lorsqu'une erreur s'est produite , ou lorsque l'observable est terminé . Ensuite, nous pouvons nous abonner à cette observable, qui l’active et dans cet abonnement, nous pouvons passer en 3 rappels (ne pas toujours passer en totalité). Un rappel à exécuter pour un succès, un rappel à une erreur et un rappel à l'achèvement. Par exemple:
const observable = Rx.Observable.create(observer => {
// create a single value and complete
observer.onNext(1);
observer.onCompleted();
});
source.subscribe(
x => console.log('onNext: %s', x), // success callback
e => console.log('onError: %s', e), // error callback
() => console.log('onCompleted') // completion callback
);
// first we log: onNext: 1
// then we log: onCompleted
Lors de la création d'un observable, il nécessite une fonction de rappel qui fournit un observateur sous forme d'argument. Sur cet observateur, vous pouvez alors appeler onNext
, onCompleted
, onError
. Ensuite, lorsque l’Observable est abonné, il appelle les rappels correspondants passés dans l’abonnement.
Observables et Promises fournissent tous deux un moyen de travailler avec async activités en JavaScript. Bien que Promises soit refuse/résolve en fonction de la réalisation d'un seul événement asynchrone (requête http), Observables peut émettre en permanence des changements d'état en fonction des observateurs qui s'y abonnent.
Une différence fondamentale entre eux est que l'observable fournit des moyens pour annuler une demande et renvoyer une nouvelle. Où comme promesse ne permettent pas une telle fonctionnalité.
En outre, Promise émet une valeur unique, tandis qu'Observable en émet plusieurs. Ainsi, lors du traitement d'une requête HTTP, Promise peut gérer une seule réponse pour la même requête, mais s'il y a plusieurs réponses à la même requête, nous devons utiliser Observable.
const promise = new Promise(resolve => {
setTimeout(() => {
resolve("Hello from a Promise!");
}, 2000);
});
promise.then(value => console.log(value));
Exemple observable maintenant. Ici aussi nous passons une fonction à observable, un observateur pour gérer la tâche asynchrone. Contrairement à resol dans la promesse, il utilise la méthode suivante et souscrit à la place de then.
Donc, les deux gère les tâches asynchrones. Voyons maintenant la différence.
const observable = new Observable(observer => {
setTimeout(() => {
observer.next('Hello from a Observable!');
}, 2000);
});
observable.subscribe(value => console.log(value));
Promesse
Observable
Vous trouverez ci-dessous quelques différences importantes dans les promesses et les observables.
Promettre
Observable
Pour une meilleure compréhension, reportez-vous au https://stackblitz.com/edit/observable-vs-promises
Bien que la réponse acceptée soit bonne en général, je ne pense pas que cela souligne le fait que lorsque vous utilisez des composants angulaires, vous voulez presque toujours utiliser un observable car il prend en charge l'annulation. Les promesses ne peuvent pas être annulées et seront résolues même si votre composant est détruit. Angular a tendance à pardonner jusqu'à ce que ce ne soit pas le cas.
Par exemple, toute détection de modification manuelle sur un composant détruit provoquera une exception:
ngOnInit() {
// promise api
this.service.getData().then(d => {
this.data = d;
this.changeDetectorRef.detectChanges();
});
// observable api
this.service.getData().pipe(takeUntil(this.unsubscribe)).subscribe((d) => {
this.data = d;
this.changeDetectorRef.detectChanges();
});
}
Si votre composant est détruit avant que la promesse soit résolue, vous obtiendrez une erreur attempt to use destroyed view
lorsque la promesse sera résolue.
Sinon, si vous utilisez des observables avec le modèle takeUntil , dès que votre composant est détruit, l'abonnement sera annulé.
C'est un peu un exemple artificiel mais l'exécution de code pour un composant détruit va probablement conduire à des bugs. Sauf si vous voulez réellement le faire pour une raison quelconque: p
Réponse courte :
(Observable} est meilleur, il a toutes les fonctionnalités Promises plus des fonctionnalités supplémentaires.
Longue réponse:
Promesses:
Observable:
Je vois beaucoup de gens utiliser l'argument selon lequel Observable est "annulable", mais il est plutôt trivial de rendre Promise "annulable"
function cancellablePromise(body) {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res; reject = rej;
body(resolve, reject)
})
promise.resolve = resolve;
promise.reject = reject;
return promise
}
// Example 1: Reject a promise prematurely
const p1 = cancellablePromise((resolve, reject) => {
setTimeout(() => resolve('10', 100))
})
p1.then(value => alert(value)).catch(err => console.error(err))
p1.reject(new Error('denied')) // expect an error in the console
// Example: Resolve a promise prematurely
const p2 = cancellablePromise((resolve, reject) => {
setTimeout(() => resolve('blop'), 100)
})
p2.then(value => alert(value)).catch(err => console.error(err))
p2.resolve(200) // expect an alert with 200
Promesse:
Un gestionnaire d'événement asynchrone - L'objet Promise représente l'achèvement éventuel (ou l'échec) d'une opération asynchrone et la valeur qui en résulte.
Syntaxe: new Promise (exécuteur);
Par exemple:
var promise_eg = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise_eg.then(function(value) {
console.log(value);
// expected output: "foo"
});
console.log(promise_eg);
À propos de Promise: Il a un pipeline, il ne retournera des valeurs qu’une fois lorsqu’il sera appelé. son gestionnaire à sens unique, donc une fois appelé, vous ne pourrez peut-être pas annuler. syntaxe utile, vous pouvez jouer, when () et then ()
Observables:
Les observables sont des collections paresseuses de valeurs multiples dans le temps. c'est vraiment une excellente approche pour les opérations asynchrones. cela peut être fait avec rxjs qui a un support croisé peut être utilisé avec angular/react etc.
son acte comme un liner. peut être multi pipeline. Ainsi, une fois défini, vous pouvez vous abonner pour obtenir des résultats de retour dans de nombreux endroits.
Syntaxe: import * as Rx from "@reactivex/rxjs";
to init:
Rx.Observable.fromEvent(button, "click"),
Rx.Subject()
etc
s'abonner: RxLogger.getInstance();
Par exemple:
import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';
range(1, 200).pipe(
filter(x => x % 2 === 1),
map(x => x + x)
).subscribe(x => console.log(x));
puisqu'il prend en charge le multi-pipeline, vous pouvez souscrire un résultat dans un emplacement différent, il a beaucoup plus de possibilités que de promesses.
Utilisation: a plus de possibilités comme map, filter, pipe, map, concatMap etc
Quelque chose que je rencontrais et qui ne ressortait pas de la première lecture du didacticiel et de la documentation était l'idée de la multidiffusion.
Assurez-vous que, par défaut, plusieurs abonnements déclenchent plusieurs exécutions dans un observable. Plusieurs abonnements à un seul appel HTTP Observable déclenchent plusieurs appels HTTP identiques, à moins que vous n'ayez .share()
(activer la multidiffusion).
Une promesse vous oblige à traiter une chose à la fois, à décompresser ses données, à gérer les exceptions, à la prise en charge linguistique de choses intéressantes telles que async/wait, et vous êtes plutôt nu.
Un observable a beaucoup de cloches et de sifflets, mais vous devez comprendre le pouvoir avec lequel vous travaillez ou il peut être utilisé à mauvais escient.
Promises et Observables nous aident à gérer les opérations asynchrones. Ils peuvent appeler certains rappels lorsque ces opérations asynchrones sont effectuées.
Angular utilise Observables qui provient de RxJS au lieu de promesses de traitement avec HTTP.
Below are some important differences in promises & Observables.