Los observables proporcionan soporte al pase de mensajes entre partes de su aplicación. Se usan frecuentemente en Angular y son la técnica recomendada para el manejo de eventos, programación asíncrona y manejar valores múltiples.
El patrón de observador es un patrón de diseño en el cual un objeto, llamado el sujeto, mantiene una lista de sus dependientes, llamados observadores y los notifica automáticamente de cambios de estado. Este patrón es similar (pero no idéntico) al patrón de diseño editor/suscriptor.
Los observables son declarativos—esto es, se define una función para publicar valores, pero no se ejecuta hasta que un consumidor se suscribe a ésta. El consumidor suscrito ahora recibe notificaciones hasta que la función termina, o hasta que anule su suscripción.
Un observable puede entregar múltiples valores de cualquier tipo—literales, mensajes o eventos dependiendo del contexto. La API para recibir valores es la misma sin importar que los valores sean entregados sincrónicamente o asincrónicamente. Ya que el observable se encarga de la lógica de inicio y desmontaje, su codigo en la aplicación sólo debe preocuparse sobre suscribirse para consumir valores, y al terminal, anular la suscripción. Sin importar que el flujo fuera presiones de teclas, una respuesta HTTP o un intervalo del temporizador, la interface para escuchar a los valores y dejar de escuchar es la misma.
Debido a estas ventajas, los observables son usados extensamente en Angular y se recomiendan para el desarrollo de aplicaciones también.
Como un emisor, puede crear una instancia Observable
que define una función suscriber. Esta es la función queque es ejecutada cuando un consumidor llama al método subscribe()
. La función suscriptora define cómo obtener o generar valores o mensajes a ser publicados.
Para ejecutar el observable que ha creado y empezar a recibir notificaciones, llame al método subscribe()
, pasando un observer. Este es un objeto JavaScript que define los manejadores para las notificaciones que recibe. La llamada subscribe()
retorna un objetoSubscription
que tiene un método unsubscribe()
, que puede llamar para dejar de recibir notificaciones.
Encuentre al continuar un ejemplo que demuestra el modelo de uso básico demostrando cómo un observable puede ser usado para emitir actualizaciones de geolocalización.
Un manejador para recibir notificaciones de un observable implementa la interface Observer
. Es un objeto que defina los métodos de retrollamada (callback) para manejar los tres tipos de notificaciones que un observador puede enviar:
Tipo de notificación | Descripción |
---|---|
next |
Requerido. Un manejador por cada valor entregado. Llamado cero o más veces después de que la ejecución empieza. |
error |
Opcional. Un manejador para una notificación de error. Un error detiene la ejecución de la instancia observable. |
complete |
Opcional. Un manejador de la notificación "ejecución completa". Los valores retrasados pueden seguir siendo entregados al siguiente manejador después de que la ejecución se completa. |
Un objeto observador puede definir cualquier combinación de estos manejadores, Si no provee un método para un tipo de notificación, el observador ignora notificaciones de ese tipo.
Una instancia Observable
empieza publicando valores sólo cuando alguien se suscribe a ésta llamando al método subscribe()
de la instancia, pasando un objeto observer para recibir las notificaciones.
En orden para mostrar cómo funcionan las suscripciones, necesitamos crear un observable. Hay un constructor que se usa para crear nuevas instancias, pero a manera ilustrativa, podemos usar algunos médotos de la librería RxJS que crea observables simples de tipos usados frecuentemente:
of(...items)
—Retorna una instanciaObservable
que entrega sincrónicamente los valores envíados como argumentos.from(iterable)
—Convierte sus argumentos a una instanciaObservable
. Éste método es usado comúnmente para convertir un array en un observable.
Acá hay un ejemplo creando y suscribiéndose a un observable simple, con son observador que muestra los mensajes recibidos en la consola:
Alternativamente, el método subscribe()
puede aceptar funciónes retrollamada en la línea para los manejadores de next
, error
, y complete
. Por ejemplo, la siguiente llamada subscribe()
es la misma a la que especifica el observador predefinido:
En cualquier caso, un manejador next
es necesario. Los manejadores error
y complete
son opcionales.
Tome en cuenta que la función next()
puede recibir, por ejemplo, cadenas de mensajes, eventos de objetos, valores numéricos o estructuras, dependiendo del contexto. Como un término general, nos referimos a la data publicada por un observable como un stream. Cualquier tipo de valor puede representarse con un observable y los valores publicados como un stream.
Use el constructor Observable
para crear un stream observable de cualquier tipo. El constructor toma como su argumento la función de suscriptor para ejecutarse cuando el método subscribe()
se ejecuta. Una función suscriptora recibe un objeto Observer
y puede publicar valores al método next()
.
Por ejemplo, para crear un observable equivalente al of(1, 2, 3)
encontrado anteriormente, debería hacer algo como esto:
Para tomar este ejemplo más lejos, podemos crear un observable que publica eventos. En este ejemplo, la función suscriptora se define en la línea.
Ahora puede usar esta función para crear un observable que publica eventos de presiones de teclas:
Un observable típico crea una ejecución nueva e independiente para cada observador suscrito. Cuando un observador se suscribe, el observable conecta un manejador de evento y entrega valores a ese observador. Cuando un segundo observador se suscribe, el observable conecta a un nuevo manejador de eventos y entrega valores a el segundo observador en una ejecución separada.
Algunas veces, en vez de comenzar una ejecución independiente ara cada suscriptor, quiere que cada suscripción obtenga los mismos valores—incluso si los valores ya empezaron e emitirse. Este sería el caso con algo como un observable de click en el objeto de documento.
Multidifusión es la práctica de difundir a una lista de múltiples suscriptores en una sola ejecución. Con un observable en multidifusión, no necesita registrar varios oyentes en el documento, prefiriendo reutilizar el primer oyente y mandar valores a cada suscriptor.
Cuando cree un observable debería determinar cómo quiere que ese observable se use y si quiere o no que se multidifusión en sus valores.
Veamos un ejemplo que cuenta de 1 a 3, con un retraso de un segundo después de que cada número es emitido.
Tome en cuenta que si se suscribe dos veces, habrán dos streams separados, cada una emitiendo valores cada segundo. Se ve parecido a esto:
Cambiando al observable a multidifusión se vería similar a esta manera:
Como los observable producen valores de manera asíncrona, try/catch no va a detectar errores efectivamente. Los errores se manejan especificando una retrollamada error
en el observador. Produciendo un error también causa que el observable limpie sus suscripciones y deje de producir valores. Un observable puede producir (haciendo retrollamada a next
), o puede completar, con la retrollamda complete
o error
.
El manejo de errores (y especialmente la recuperación de un error) se cubre en mayor detalle más adelante.