Una de las características clave de NestJS es su compatibilidad con paradigmas de programación asíncrona, en particular la transición de promesas a observables. En este artículo, profundizaremos en el concepto de promesas y observables en NestJS, exploraremos por qué los observables son ventajosos y proporcionaremos ejemplos completos que cubren varios escenarios.
Promesas y observables
Promesas 🙏🏼
Las promesas son una parte fundamental del modelo de programación asíncrona de JavaScript. Representan un proxy de un valor que estará disponible o de un error que se producirá.
Las promesas ofrecen una alternativa más limpia a los enfoques basados en callbacks, permitiendo un código más legible y fácil de mantener.
En NestJS, las promesas se utilizan ampliamente para manejar operaciones asíncronas como consultas a bases de datos, peticiones HTTP y E/S de archivos. He aquí un ejemplo básico del uso de promesas en un servicio NestJS:
@Injectable()
export class UserService {
async findAll(): Promise<User[]> {
return await this.userModel.find().exec();
}
}
Observables 👀
Los observables, por otro lado, son una abstracción más potente para manejar flujos de datos asíncronos. Permiten manejar múltiples valores a lo largo del tiempo, lo que los hace idóneos para situaciones como la gestión de eventos, el almacenamiento de datos en caché y las actualizaciones en tiempo real.
NestJS aprovecha los observables a través de bibliotecas como RxJS, permitiendo paradigmas de programación reactiva dentro de su marco. A continuación se explica cómo utilizar observables en un servicio NestJS:
import { Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { User } from './user.interface';
@Injectable()
export class UserService {
findAll(): Observable<User[]> {
return from(this.userModel.find().exec());
}
}
Ventajas de los Observables en NestJS
Procesamiento asíncrono de flujos
Los observables sobresalen en el manejo de flujos de datos de forma asíncrona. En escenarios donde los datos llegan de forma incremental o en tiempo real, los observables ofrecen una forma más natural y eficiente de procesar estos datos en comparación con las promesas.
Componibilidad y gestión de errores
Los observables proporcionan potentes operadores que permiten componer fácilmente operaciones asíncronas.
Operadores como map
, filter
y mergeMap
permiten a los desarrolladores manipular flujos de datos con facilidad.
Además, los observables ofrecen sólidos mecanismos de gestión de errores, lo que permite que los errores se propaguen con gracia a través del flujo.
Observables fríos y calientes
Hay dos tipos de observables: fríos y calientes. Los observables fríos comienzan a producir valores cuando un consumidor se suscribe a ellos, lo que los hace adecuados para escenarios en los que cada consumidor necesita su propio flujo independiente de datos.
Los observables calientes, por otro lado, emiten valores independientemente de si hay algún suscriptor, lo que los hace ideales para escenarios como el manejo de eventos.
Uso de Observables en NestJS: Ejemplos
Recuperación básica de datos
Empecemos con un ejemplo básico de uso de observables para recuperar datos de una base de datos en un controlador NestJS:
import { Controller, Get } from '@nestjs/common';
import { Observable } from 'rxjs';
import { User } from './user.interface';
import { UserService } from './user.service';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
findAll(): Observable<User[]> {
return this.userService.findAll();
}
}
Actualizaciones en tiempo real con WebSockets
Ahora, vamos a explorar un escenario más avanzado en el que utilizamos observables para empujar actualizaciones en tiempo real a los clientes utilizando WebSockets:
import { WebSocketGateway, WebSocketServer, SubscribeMessage } from '@nestjs/websockets';
import { Server } from 'socket.io';
import { Observable } from 'rxjs';
import { User } from './user.interface';
import { UserService } from './user.service';
@WebSocketGateway()
export class UserGateway {
constructor(private readonly userService: UserService) {}
@WebSocketServer() server: Server;
@SubscribeMessage('getUsers')
getUsers(): Observable<User[]> {
return this.userService.findAll();
}
}
Sección FAQ
P: ¿Cuándo debo utilizar promesas en lugar de observables en NestJS?
R: Las promesas son adecuadas para operaciones asíncronas simples que implican un solo valor o un evento de una sola vez. Si está tratando con flujos de datos o necesita una composición más avanzada y gestión de errores, los observables son una mejor opción.
P: ¿Son los observables más difíciles de entender que las promesas?
R: Aunque los observables tienen una curva de aprendizaje más pronunciada que las promesas, ofrecen más potencia expresiva y flexibilidad, especialmente en escenarios asíncronos complejos.
P: ¿Puedo mezclar promesas y observables en NestJS?
R: Sí, NestJS proporciona interoperabilidad sin fisuras entre promesas y observables, lo que le permite elegir la mejor herramienta para el trabajo en cualquier escenario dado.
Conclusión
En conclusión, NestJS ofrece un sólido soporte tanto para promesas como para observables, permitiendo a los desarrolladores elegir el paradigma de programación asíncrona más apropiado para sus aplicaciones.
Mientras que las promesas siguen siendo un bloque de construcción fundamental, los observables desbloquean un nuevo nivel de expresividad y flexibilidad, particularmente en escenarios que implican flujos de datos y actualizaciones en tiempo real. Al dominar la transición de promesas a observables, los desarrolladores pueden liberar todo el potencial de la programación reactiva dentro del marco NestJS.