¿Cuál es la diferencia entre promesas y observables?

Resuelto Rohit asked hace 8 años • 35 respuestas

¿Cuál es la diferencia entre Promisey Observableen Angular?

Un ejemplo de cada uno sería útil para comprender ambos casos. ¿En qué escenario podemos utilizar cada caso?

Rohit avatar May 21 '16 22:05 Rohit
Aceptado

Promesa

A Promisemaneja un único evento cuando una operación asíncrona se completa o falla.

Nota: Existen Promisebibliotecas que admiten la cancelación, pero ES6 Promiseno lo hace hasta ahora.

Observable

An Observablees como a Stream(en muchos idiomas) y le permite pasar cero o más eventos donde se llama a la devolución de llamada para cada evento.

A menudo Observablese prefiere Promiseporque ofrece las características de Promisey más. No Observableimporta si desea manejar 0, 1 o varios eventos. Puede utilizar la misma API en cada caso.

ObservableTambién tiene la ventaja Promisede ser cancelable . Si el resultado de una solicitud HTTP a un servidor o alguna otra operación asincrónica costosa ya no es necesario, un le Subscriptionpermite Observablecancelar la suscripción, mientras que Promiseeventualmente llamará a la devolución de llamada exitosa o fallida incluso cuando no necesite el notificación o el resultado que proporciona.

Mientras que a Promisecomienza inmediatamente, Observablesolo comienza si te suscribes. Es por eso que los Observables se llaman vagos.

Observable proporciona operadores como map,,, ... similares a una matrizforEachreduce

También hay operadores potentes como retry(), o replay(), ... que suelen ser bastante útiles. Una lista de operadores enviados con rxjs

La ejecución diferida le permite crear una cadena de operadores antes de que se ejecute el observable mediante la suscripción, para realizar un tipo de programación más declarativa.

Günter Zöchbauer avatar May 21 '2016 17:05 Günter Zöchbauer

Ambos Promisesy Observablesnos proporcionan abstracciones que nos ayudan a lidiar con la naturaleza asincrónica de nuestras aplicaciones. Günter y @Relu señalaron claramente la diferencia entre ellos .

Dado que un fragmento de código vale más que mil palabras, veamos el siguiente ejemplo para entenderlo más fácilmente.

Gracias @Christoph Burgdorf por el fantástico artículo.


Angular usa Rx.js Observables en lugar de promesas para tratar con HTTP.

Suponga que está creando una función de búsqueda que debería mostrarle resultados instantáneamente a medida que escribe. Suena familiar, pero hay muchos desafíos que conlleva esa tarea.

  • No queremos llegar al punto final del servidor cada vez que el usuario presiona una tecla. Debería inundarlos con una tormenta de solicitudes HTTP . Básicamente, solo queremos presionarlo una vez que el usuario haya dejado de escribir en lugar de cada pulsación de tecla.
  • No llegue al punto final de búsqueda con los mismos parámetros de consulta para solicitudes posteriores.
  • Lidiar con respuestas desordenadas. Cuando tenemos varias solicitudes en curso al mismo tiempo, debemos tener en cuenta los casos en los que regresan en un orden inesperado. Imaginemos que primero escribimos computadora , nos detenemos, sale una solicitud, escribimos auto , nos detenemos, sale una solicitud. Ahora tenemos dos solicitudes en vuelo. Desafortunadamente, la solicitud que contiene los resultados de la computadora regresa después de la solicitud que contiene los resultados del automóvil .

La demostración constará simplemente de dos archivos: app.tsy wikipedia-service.ts. Sin embargo, en un escenario del mundo real, lo más probable es que dividiéramos aún más las cosas.


A continuación se muestra una implementación basada en Promesa que no maneja ninguno de los casos extremos descritos.

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]);
  }
}

Estamos inyectando el Jsonpservicio para realizar una solicitud GET en la API de Wikipedia con un término de búsqueda determinado. Observe que llamamos toPromisepara pasar de an Observable<Response>a a Promise<Response>. Finalmente terminaremos con a Promise<Array<string>>como tipo de retorno de nuestro método de búsqueda.

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);
  }
}

Aquí tampoco hay mucha sorpresa. Inyectamos nuestra WikipediaServicey exponemos su funcionalidad a través de un método de búsqueda en la plantilla. La plantilla simplemente se vincula a keyup y llama search(term.value).

Desenvolvemos el resultado de la Promesa que devuelve el método de búsqueda de WikipediaService y lo exponemos como una simple matriz de cadenas a la plantilla para que podamos *ngForrecorrerlo y crear una lista para nosotros.

Vea el ejemplo de implementación basada en promesas en Plunker


Donde realmente brillan los observables

Cambiemos nuestro código para no dañar el punto final con cada pulsación de tecla, sino solo enviar una solicitud cuando el usuario dejó de escribir durante 400 ms.

Para revelar tales superpoderes, primero necesitamos obtener un Observable<string>que contenga el término de búsqueda que ingresa el usuario. En lugar de vincularnos manualmente al evento keyup, podemos aprovechar la formControldirectiva de Angular. Para utilizar esta directiva, primero debemos importarla ReactiveFormsModulea nuestro módulo de aplicación.

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 {}

Una vez importado, podemos usar formControl desde nuestra plantilla y configurarlo con el nombre "término".

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

En nuestro componente, creamos una instancia de FormControlfrom @angular/formy la exponemos como un campo bajo el término de nombre de nuestro componente.

Detrás de escena, term expone automáticamente una Observable<string>propiedad as valueChangesa la que podemos suscribirnos. Ahora que tenemos un Observable<string>, superar la entrada del usuario es tan fácil como llamar debounceTime(400)a nuestro Observable. Esto devolverá un nuevo valor Observable<string>que solo emitirá un nuevo valor cuando no hayan llegado nuevos valores durante 400 ms.

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

Sería un desperdicio de recursos enviar otra solicitud para un término de búsqueda cuyos resultados nuestra aplicación ya muestra. Todo lo que tenemos que hacer para lograr el comportamiento deseado es llamar al distinctUntilChangedoperador inmediatamente después de llamar.debounceTime(400)

Vea el ejemplo de implementación observable en Plunker.

Para lidiar con respuestas desordenadas, consulte el artículo completo http://blog.thinktram.io/angular/2016/01/06/ Taking-advantage-of-observables-in-angular2.html

En la medida en que uso HTTP en Angular, estoy de acuerdo en que en los casos de uso normales no hay mucha diferencia al usar Observable sobre Promise. Ninguna de las ventajas es realmente relevante en la práctica. Espero poder ver algún caso de uso avanzado en el futuro :)


Aprende más

  • https://angular-2-training-book.rangle.io/handout/observables/
  • https://angular.io/tutorial/toh-pt6#observables
trungvose avatar Oct 19 '2016 15:10 trungvose

Tanto Promises como Observables nos ayudarán a trabajar con las funcionalidades asincrónicas en JavaScript. Son muy similares en muchos casos; sin embargo, todavía existen algunas diferencias entre los dos: las promesas son valores que se resolverán de asynchronousmanera similar a las llamadas HTTP. Por otro lado, los observables tratan de una secuencia de eventos asincrónicos . Las principales diferencias entre ellos se enumeran a continuación:

Promesa:

  • tener una tubería
  • normalmente sólo se utiliza con devolución de datos asíncronos
  • no es fácil cancelar

Observable:

  • son cancelables
  • son reintentables por naturaleza, como reintentar y reintentarCuando
  • transmitir datos en múltiples canalizaciones
  • tener operaciones tipo matriz como mapa, filtro, etc.
  • Se puede crear a partir de otras fuentes, como eventos.
  • son funciones, que se podrían suscribir más adelante

Además, he creado la imagen gráfica a continuación para mostrar las diferencias visualmente:

Imagen de promesas y observables

Alireza avatar May 07 '2017 06:05 Alireza

Hay una desventaja de los Observables que faltan en las respuestas. Las promesas permiten utilizar las funciones async/await de ES7. Con ellos puedes escribir código asincrónico como si fuera una llamada a función sincrónica, por lo que ya no necesitas devoluciones de llamada. La única posibilidad que tienen los Observables de hacer esto es convertirlos en Promesas. Pero cuando las conviertes en Promesas, solo puedes volver a tener un valor de retorno:

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

Lectura adicional: ¿Cómo puedo "esperar" en un Rx Observable?

besserwisser avatar Jun 28 '2017 20:06 besserwisser

Promesas

  1. Definición: le ayuda a ejecutar funciones de forma asincrónica y a utilizar sus valores de retorno (o excepciones), pero solo una vez cuando se ejecuta.
  2. No perezoso
  3. No cancelable (existen bibliotecas de Promise que admiten la cancelación, pero ES6 Promise no lo hace hasta ahora). Las dos decisiones posibles son
    • Rechazar
    • Resolver
  4. No se puede volver a intentar (las promesas deben tener acceso a la función original que devolvió la promesa para tener la capacidad de reintentar, lo cual es una mala práctica)

Observables

  1. Definición: le ayuda a ejecutar funciones de forma asincrónica y a utilizar sus valores de retorno en una secuencia continua ( varias veces ) cuando se ejecuta.
  2. Por defecto, es diferido ya que emite valores a medida que avanza el tiempo.
  3. Tiene muchos operadores, lo que simplifica el esfuerzo de codificación.
  4. Se puede usar un reintento de operador para reintentar cuando sea necesario, también si necesitamos reintentar el observable en función de algunas condiciones, se puede usar retryWhen .

Nota : Una lista de operadores junto con sus diagramas interactivos está disponible aquí en **RxMarbles.com **

Aravind avatar Jan 09 '2017 18:01 Aravind