<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>RxJs · DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/series/rxjs/</link><description>Blog de tecnología, programación y electrónica, para compartir conocimientos, experiencias y tutoriales con este apasionante mundo.</description><generator>Hugo</generator><language>es-CO</language><copyright>Copyright © 2026 DacaDev. All rights reserved.</copyright><lastBuildDate>Thu, 11 Jun 2026 00:00:00 -0500</lastBuildDate><atom:link href="https://blog.dacadev.com/series/rxjs/index.xml" rel="self" type="application/rss+xml"/><image><url>https://blog.dacadev.com/images/blog-logo.png</url><title>DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/</link></image><item><title>RxJs: Peticiones HTTP/AJAX con rxjs/ajax y catchError</title><link>https://blog.dacadev.com/typescript/rxjs/peticiones-ajax-rxjs/</link><pubDate>Thu, 11 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/peticiones-ajax-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende peticiones ajax rxjs con rxjs/ajax, getJSON, métodos HTTP y catchError rxjs para manejar errores en streams.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/ajax/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#fetch-frente-a-rxjsajax"&gt;fetch frente a rxjs/ajax&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#rxjs-ajax-para-peticiones-http"&gt;rxjs ajax para peticiones HTTP&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#catcherror-rxjs-recuperar-el-stream-ante-fallos"&gt;catchError rxjs: recuperar el stream ante fallos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ajaxgetjson-para-consumir-respuestas-json"&gt;ajax.getJSON para consumir respuestas JSON&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#métodos-post-put-y-delete-con-rxjsajax"&gt;Métodos post, put y delete con rxjs/ajax&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#configuración-avanzada-con-objeto"&gt;Configuración avanzada con objeto&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#composición-con-cancelación"&gt;Composición con cancelación&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En aplicaciones frontend, las &lt;strong&gt;peticiones ajax rxjs&lt;/strong&gt; resultan útiles cuando el tráfico HTTP no es un evento aislado, sino parte de un flujo: búsquedas con cancelación, reintentos, composición con eventos de UI o coordinación entre varias fuentes asíncronas. &lt;code&gt;fetch&lt;/code&gt; cubre bien el caso imperativo basado en promesas, pero &lt;code&gt;rxjs/ajax&lt;/code&gt; integra las peticiones HTTP directamente con observables, operadores y suscripciones.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar los &lt;a href="https://blog.dacadev.com/typescript/operadores-combinacion-observables/"



 


&gt;operadores de combinación&lt;/a&gt; y cerraremos la serie abordando &lt;code&gt;rxjs/ajax&lt;/code&gt;, &lt;code&gt;ajax.getJSON&lt;/code&gt;, métodos HTTP y &lt;code&gt;catchError rxjs&lt;/code&gt; para manejar fallos sin romper el flujo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="fetch-frente-a-rxjsajax"&gt;fetch frente a rxjs/ajax&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fetch&lt;/code&gt; es el estándar moderno del navegador para ejecutar peticiones HTTP. Su API está basada en &lt;code&gt;Promise&lt;/code&gt;, por lo que encaja bien cuando necesitas una única respuesta y un flujo de control lineal.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://api.github.com/users?per_page=5&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;manejaErrores&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;ok&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;throw&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Error&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;statusText&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fetch&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;manejaErrores&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#c678dd"&gt;catch&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La limitación aparece cuando la petición debe integrarse con otros streams. Una &lt;code&gt;Promise&lt;/code&gt; no tiene el concepto de suscripción, no emite múltiples valores y no se cancela por sí misma al dejar de interesarte el resultado. &lt;code&gt;fetch&lt;/code&gt; puede abortarse con &lt;code&gt;AbortController&lt;/code&gt;, pero esa cancelación queda como una responsabilidad externa que debes coordinar manualmente.&lt;/p&gt;
&lt;p&gt;Con RxJS, en cambio, la suscripción representa el ciclo de vida del trabajo asíncrono. En &lt;code&gt;rxjs/ajax&lt;/code&gt;, cancelar la suscripción aborta la petición subyacente basada en &lt;code&gt;XMLHttpRequest&lt;/code&gt;, lo cual encaja naturalmente con operadores como &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt; o &lt;code&gt;debounceTime&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;fetch&lt;/code&gt; para flujos simples basados en una sola respuesta. Usa &lt;code&gt;rxjs/ajax&lt;/code&gt; cuando la petición forma parte de una arquitectura reactiva y necesitas composición, cancelación por suscripción o manejo declarativo de errores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="rxjs-ajax-para-peticiones-http"&gt;rxjs ajax para peticiones HTTP&lt;/h2&gt;
&lt;p&gt;El módulo &lt;a href="https://rxjs.dev/api/ajax/ajax"




 target="_blank"
 


&gt;&lt;code&gt;rxjs/ajax&lt;/code&gt;&lt;/a&gt; expone la función &lt;code&gt;ajax&lt;/code&gt;, que devuelve un observable. Al suscribirte, se ejecuta la petición; al desuscribirte, se cancela si todavía está pendiente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;login&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;html_url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://api.github.com/users?per_page=5&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;ajaxResponse&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajaxResponse&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;users&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;users&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El observable emitido por &lt;code&gt;ajax&lt;/code&gt; no entrega únicamente el cuerpo. Entrega un &lt;code&gt;AjaxResponse&amp;lt;T&amp;gt;&lt;/code&gt; con metadatos como &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;response&lt;/code&gt;, &lt;code&gt;request&lt;/code&gt; y &lt;code&gt;xhr&lt;/code&gt;. Esto es útil cuando la lógica depende del código HTTP, encabezados o detalles del transporte.&lt;/p&gt;
&lt;p&gt;Para obtener solo el cuerpo, el patrón habitual consiste en aplicar &lt;code&gt;map&lt;/code&gt; sobre &lt;code&gt;response&lt;/code&gt;. En versiones modernas de RxJS, importar operadores desde &lt;code&gt;rxjs&lt;/code&gt; mantiene el código conciso y compatible con el estilo recomendado.&lt;/p&gt;
&lt;h2 id="catcherror-rxjs-recuperar-el-stream-ante-fallos"&gt;catchError rxjs: recuperar el stream ante fallos&lt;/h2&gt;
&lt;p&gt;El operador &lt;a href="https://rxjs.dev/api/operators/catchError"




 target="_blank"
 


&gt;&lt;code&gt;catchError&lt;/code&gt;&lt;/a&gt; intercepta errores dentro de un observable y debe retornar un nuevo observable o un valor compatible con &lt;code&gt;ObservableInput&lt;/code&gt;. Esto permite reemplazar el flujo fallido por un valor seguro, reintentar con otra fuente o propagar un error enriquecido.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/ajax/marble-catcherror_hu_59aa604728b2d608.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El diagrama muestra el punto clave: cuando ocurre un error, &lt;code&gt;catchError&lt;/code&gt; reemplaza el stream original por otro observable. Si no retornas un observable, la cadena queda en un estado inválido.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;AjaxError&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;login&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://api.github.com/users?per_page=5&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;atrapaError&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;AjaxError&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([] &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt;[]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;atrapaError&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;users&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;users&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo, el consumidor siempre recibe un arreglo. Si la petición falla, la UI puede renderizar un estado vacío sin romper la suscripción. Esta decisión es adecuada para listas tolerantes a fallo, pero no para operaciones donde ocultar el error afectaría consistencia o seguridad.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/ajax/console-catcherror_hu_4f892a08d295a73c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La salida de consola confirma que el error se captura dentro del pipeline y el stream continúa con el valor de reemplazo definido por &lt;code&gt;of&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No uses &lt;code&gt;catchError&lt;/code&gt; para silenciar errores críticos de forma indiscriminada. Retorna valores de fallback solo cuando el dominio lo permite; en otros casos, transforma el error y propágalo con &lt;code&gt;throwError&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="ajaxgetjson-para-consumir-respuestas-json"&gt;ajax.getJSON para consumir respuestas JSON&lt;/h2&gt;
&lt;p&gt;Cuando solo necesitas el cuerpo JSON, &lt;code&gt;ajax.getJSON&lt;/code&gt; reduce el ruido del &lt;code&gt;AjaxResponse&lt;/code&gt;. Este método ejecuta una petición &lt;code&gt;GET&lt;/code&gt;, parsea la respuesta como JSON y permite enviar encabezados.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;DelayResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Record&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;origin&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://httpbin.org/delay/1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;DelayResponse&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;mi-token&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;1234&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;response$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;data&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en getJSON&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;getJSON&lt;/code&gt; es una buena opción para consultas simples donde no necesitas inspeccionar &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;xhr&lt;/code&gt; o encabezados de respuesta. Si esos metadatos importan, usa &lt;code&gt;ajax&lt;/code&gt; directamente para conservar el contexto completo.&lt;/p&gt;
&lt;h2 id="métodos-post-put-y-delete-con-rxjsajax"&gt;Métodos post, put y delete con rxjs/ajax&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rxjs/ajax&lt;/code&gt; también expone métodos especializados para verbos HTTP comunes: &lt;code&gt;ajax.get&lt;/code&gt;, &lt;code&gt;ajax.post&lt;/code&gt;, &lt;code&gt;ajax.put&lt;/code&gt;, &lt;code&gt;ajax.patch&lt;/code&gt; y &lt;code&gt;ajax.delete&lt;/code&gt;. Todos retornan observables y pueden participar en el mismo pipeline de operadores.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserPayload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HttpBinResponse&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;T&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;json&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;T&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://httpbin.org/anything/users&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;x-client&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs-demo&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;post&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HttpBinResponse&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserPayload&lt;/span&gt;&amp;gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;, { &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Ada&amp;#39;&lt;/span&gt; }, &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en POST&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;put&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HttpBinResponse&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserPayload&lt;/span&gt;&amp;gt;&amp;gt;(&lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;/1`&lt;/span&gt;, { &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Ada Lovelace&amp;#39;&lt;/span&gt; }, &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en PUT&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;delete&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;/1`&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en DELETE&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La forma especializada es legible cuando el método HTTP es fijo y la configuración es pequeña. Para casos con más parámetros, la forma de objeto suele ser más mantenible.&lt;/p&gt;
&lt;h2 id="configuración-avanzada-con-objeto"&gt;Configuración avanzada con objeto&lt;/h2&gt;
&lt;p&gt;La función &lt;code&gt;ajax&lt;/code&gt; acepta un objeto de configuración. Esta variante agrupa &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;responseType&lt;/code&gt; y otros parámetros en una sola estructura, evitando firmas largas y facilitando la composición dinámica.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CreateUserRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;role&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;editor&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;viewer&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CreateUserResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;json&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;CreateUserRequest&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;requestBody&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;CreateUserRequest&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Grace Hopper&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;role&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;createUser$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;CreateUserResponse&lt;/span&gt;&amp;gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://httpbin.org/anything/users&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;method&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;Authorization&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Bearer demo-token&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;body&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;requestBody&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;responseType&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;No fue posible crear el usuario&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;createUser$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;usuario creado&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esta forma es especialmente útil en servicios donde construyes peticiones desde parámetros de dominio. También facilita extraer una función reutilizable que retorne un observable tipado sin ejecutar la petición hasta que exista una suscripción.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Mantén las funciones HTTP como fábricas de observables: reciben parámetros de dominio y retornan &lt;code&gt;Observable&amp;lt;T&amp;gt;&lt;/code&gt;. Evita suscribirte dentro del servicio si el consumidor necesita cancelar, componer o manejar errores en una capa superior.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="composición-con-cancelación"&gt;Composición con cancelación&lt;/h2&gt;
&lt;p&gt;Una de las ventajas prácticas de &lt;code&gt;rxjs/ajax&lt;/code&gt; aparece en búsquedas o autocompletados. &lt;code&gt;switchMap&lt;/code&gt; cancela la petición anterior cuando llega un nuevo término, evitando condiciones de carrera y respuestas obsoletas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#search&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;results$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;unknown&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#98c379"&gt;`/api/search?q=&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;encodeURIComponent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([])),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;results$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;results&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;renderResults&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;results&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con &lt;code&gt;fetch&lt;/code&gt;, este patrón requiere coordinar manualmente &lt;code&gt;AbortController&lt;/code&gt; para cada búsqueda pendiente. Con RxJS, la cancelación es una consecuencia directa de la desuscripción que &lt;code&gt;switchMap&lt;/code&gt; realiza sobre el observable interno anterior.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rxjs/ajax&lt;/code&gt; convierte las peticiones HTTP en streams composables. Esta integración permite mapear respuestas, centralizar errores con &lt;code&gt;catchError&lt;/code&gt;, cancelar trabajo pendiente mediante desuscripción y coordinar tráfico HTTP con eventos de interfaz o temporizadores.&lt;/p&gt;
&lt;p&gt;Con este artículo cerramos la serie RxJs: partimos de la naturaleza de los observables, recorrimos funciones de creación, operadores básicos, transformación, combinación y finalmente peticiones AJAX. El objetivo común fue diseñar flujos asíncronos explícitos, cancelables y mantenibles usando las primitivas reactivas correctas.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores de combinación de observables</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-combinacion-observables/</link><pubDate>Tue, 09 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-combinacion-observables/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a combinar observables RxJS con startWith, endWith, concat, merge, combineLatest y forkJoin en flujos reactivos reales.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#startwith-inicializar-un-observable-con-una-primera-emisión"&gt;&lt;code&gt;startWith&lt;/code&gt;: inicializar un observable con una primera emisión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#endwith-añadir-emisiones-al-completar-el-stream"&gt;&lt;code&gt;endWith&lt;/code&gt;: añadir emisiones al completar el stream&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#concat-combinar-observables-rxjs-de-forma-secuencial"&gt;&lt;code&gt;concat&lt;/code&gt;: combinar observables RxJS de forma secuencial&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#merge-combinar-emisiones-concurrentes-en-un-solo-observable"&gt;&lt;code&gt;merge&lt;/code&gt;: combinar emisiones concurrentes en un solo observable&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#combinelatest-sincronizar-los-últimos-valores-emitidos"&gt;&lt;code&gt;combineLatest&lt;/code&gt;: sincronizar los últimos valores emitidos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#forkjoin-esperar-la-última-emisión-de-observables-finitos"&gt;&lt;code&gt;forkJoin&lt;/code&gt;: esperar la última emisión de observables finitos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cómo-elegir-entre-concat-merge-combinelatest-y-forkjoin"&gt;Cómo elegir entre &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt; y &lt;code&gt;forkJoin&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando una aplicación reactiva necesita coordinar eventos de teclado, clics, respuestas HTTP y temporizadores, el reto no está solo en crear observables, sino en decidir cómo sincronizar sus emisiones. &lt;strong&gt;Combinar observables RxJS&lt;/strong&gt; correctamente evita acoplamiento innecesario, carreras difíciles de depurar y estados intermedios inconsistentes en la interfaz.&lt;/p&gt;
&lt;p&gt;En este artículo analizaremos operadores y funciones de combinación de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;: &lt;code&gt;startWith&lt;/code&gt;, &lt;code&gt;endWith&lt;/code&gt;, &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt; y &lt;code&gt;forkJoin&lt;/code&gt;. Cada uno resuelve un problema distinto: inicializar un stream, añadir una emisión final, concatenar secuencias, mezclar eventos concurrentes, sincronizar últimos valores o esperar a que varias fuentes finalicen.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de revisar &lt;a href="https://blog.dacadev.com/typescript/operadores-no-tan-comunes-rxjs/"



 


&gt;Operadores no tan comunes&lt;/a&gt; y después continuaremos con &lt;a href="https://blog.dacadev.com/typescript/peticiones-ajax-rxjs/"



 


&gt;Ajax con RxJs&lt;/a&gt;. Aquí nos enfocamos en operadores de combinación y en cómo elegir el adecuado según el comportamiento esperado del flujo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="startwith-inicializar-un-observable-con-una-primera-emisión"&gt;&lt;code&gt;startWith&lt;/code&gt;: inicializar un observable con una primera emisión&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;startWith&lt;/code&gt;&lt;/strong&gt; permite definir una o varias emisiones iniciales antes de que el observable fuente empiece a entregar sus propios valores. Es útil cuando una suscripción necesita un estado inicial inmediato, por ejemplo, para pintar una vista antes de que ocurra el primer evento real.&lt;/p&gt;
&lt;p&gt;En el diagrama, el valor &lt;code&gt;a&lt;/code&gt; se emite antes que cualquier valor proveniente del observable original. La suscripción no necesita esperar a que la fuente produzca el primer dato.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-startwith_hu_3f50febfe8c561c5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Ejemplo de uso:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Este flujo primero emite &lt;code&gt;3&lt;/code&gt; por efecto de &lt;code&gt;startWith(3)&lt;/code&gt; y después continúa con las emisiones de &lt;code&gt;of(1, 2, 3)&lt;/code&gt;. En escenarios de UI, este patrón suele aparecer cuando necesitas mostrar un valor por defecto antes de recibir eventos del usuario o datos remotos.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;startWith&lt;/code&gt; no modifica la fuente original; crea un nuevo observable con emisiones prefijadas. Esta distinción mantiene la composición declarativa del pipeline.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="endwith-añadir-emisiones-al-completar-el-stream"&gt;&lt;code&gt;endWith&lt;/code&gt;: añadir emisiones al completar el stream&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;endWith&lt;/code&gt;&lt;/strong&gt; trabaja en el extremo opuesto de &lt;code&gt;startWith&lt;/code&gt;. En lugar de emitir valores al inicio, agrega emisiones al final, justo cuando el observable fuente completa.&lt;/p&gt;
&lt;p&gt;Esto implica una condición importante: la fuente debe completar. Si el observable nunca envía la señal de &lt;code&gt;complete&lt;/code&gt;, &lt;code&gt;endWith&lt;/code&gt; no tendrá oportunidad de emitir sus valores finales.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-endwith_hu_1dbaa30bd447d3be.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El modo de uso puede combinar ambos operadores:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;endWith&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;endWith&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado incluye las emisiones iniciales, los valores originales y las emisiones finales:&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/console-start-endwith_hu_2d98486731811f2a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;endWith&lt;/code&gt; es apropiado para flujos finitos donde quieres señalar un cierre lógico, adjuntar un marcador final o emitir un estado de terminación después de procesar una secuencia.&lt;/p&gt;
&lt;h2 id="concat-combinar-observables-rxjs-de-forma-secuencial"&gt;&lt;code&gt;concat&lt;/code&gt;: combinar observables RxJS de forma secuencial&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;concat&lt;/code&gt;&lt;/strong&gt; concatena observables uno detrás de otro. Se suscribe al primer observable, espera a que complete y solo entonces avanza al siguiente. El resultado es un observable nuevo que conserva el orden secuencial de las fuentes.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;concat&lt;/code&gt; es una función de creación/combinación; no debe confundirse con &lt;code&gt;concatMap&lt;/code&gt;. &lt;code&gt;concatMap&lt;/code&gt; proyecta cada emisión hacia un observable interno y los aplana en orden. &lt;code&gt;concat&lt;/code&gt;, en cambio, recibe fuentes ya definidas y las ejecuta secuencialmente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El diagrama muestra que las emisiones del segundo stream no empiezan hasta que el primero completa. Esta propiedad es crítica cuando el orden tiene semántica de negocio, por ejemplo, inicializar una configuración antes de consumir un flujo dependiente.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-concat_hu_ee64538cd07c1214.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Su modo de uso es:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;concat&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;take&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;concat&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// un iterable u objeto compatible con ObservableInput
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El primer &lt;code&gt;intervalo$.pipe(take(2))&lt;/code&gt; emite dos valores y completa. Después se ejecuta el segundo &lt;code&gt;intervalo$.pipe(take(3))&lt;/code&gt;. Finalmente, &lt;code&gt;concat&lt;/code&gt; consume el arreglo &lt;code&gt;[1, 2, 3, 5]&lt;/code&gt; como una fuente compatible con &lt;code&gt;ObservableInput&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;El resultado respeta ese orden:&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/console-concat_hu_4f320d74fd3067a2.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La restricción operativa más importante es que cada fuente debe completar para que &lt;code&gt;concat&lt;/code&gt; avance. Si el primer observable es infinito, el segundo nunca se suscribirá.&lt;/p&gt;
&lt;h2 id="merge-combinar-emisiones-concurrentes-en-un-solo-observable"&gt;&lt;code&gt;merge&lt;/code&gt;: combinar emisiones concurrentes en un solo observable&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/strong&gt; combina las emisiones de dos o más observables en un único stream de salida. A diferencia de &lt;code&gt;concat&lt;/code&gt;, no espera a que una fuente complete para suscribirse a la siguiente; todas las fuentes activas pueden emitir de forma concurrente.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; completa únicamente cuando todos los observables de entrada han completado. En streams de eventos del DOM, como &lt;code&gt;click&lt;/code&gt; o &lt;code&gt;keyup&lt;/code&gt;, esto normalmente significa que el flujo permanece activo durante toda la vida de la página, salvo que se aplique una estrategia de finalización explícita.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-merge_hu_2109f797e699b06b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Modo de uso:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;merge&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;merge&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso, ambos observables se transforman para emitir únicamente el tipo de evento. El stream resultante recibe tanto &lt;code&gt;keyup&lt;/code&gt; como &lt;code&gt;click&lt;/code&gt;, sin imponer un orden artificial entre ellos.&lt;/p&gt;
&lt;p&gt;El resultado en consola evidencia que ambos eventos se combinan en una sola suscripción:&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/console-merge-events_hu_13a76b79f5c14923.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; es una buena elección cuando las fuentes son independientes y quieres reaccionar a cualquiera de ellas con la misma lógica de downstream.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="combinelatest-sincronizar-los-últimos-valores-emitidos"&gt;&lt;code&gt;combineLatest&lt;/code&gt;: sincronizar los últimos valores emitidos&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt; combina múltiples observables y emite un arreglo con el último valor disponible de cada fuente. Su comportamiento tiene una regla clave: no emite hasta que todos los observables participantes hayan emitido al menos una vez.&lt;/p&gt;
&lt;p&gt;Después de esa primera sincronización, cada nueva emisión de cualquier fuente produce una nueva salida con el valor actualizado de esa fuente y los últimos valores conocidos de las demás. Esto es especialmente útil para formularios, filtros, coordenadas de UI y estados derivados.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-combinelatest_hu_5536863cb22096a9.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El código de uso puede ser parecido a esto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;combineLatest&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;placeholder&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;email@example.com&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;placeholder&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;*******&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;append&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// helper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;elem&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;HTMLElement&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;elem&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;target&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;combineLatest&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El ejemplo conserva la firma posicional usada durante mucho tiempo en RxJS. En código moderno, especialmente con RxJS 7+, suele preferirse la firma con arreglo porque escala mejor y es más explícita:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;combineLatest&lt;/span&gt;([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;También conviene considerar que &lt;code&gt;pluck&lt;/code&gt; pertenece a un estilo más antiguo de transformación. Para proyectos nuevos, &lt;code&gt;map&lt;/code&gt; con acceso explícito suele ser más legible y compatible con la evolución del ecosistema.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si una de las fuentes de &lt;code&gt;combineLatest&lt;/code&gt; nunca emite, el observable combinado tampoco emitirá. Para evitar estados bloqueados, puedes inicializar fuentes con &lt;code&gt;startWith&lt;/code&gt; cuando tenga sentido semántico.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="forkjoin-esperar-la-última-emisión-de-observables-finitos"&gt;&lt;code&gt;forkJoin&lt;/code&gt;: esperar la última emisión de observables finitos&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;forkJoin&lt;/code&gt;&lt;/strong&gt; emite una sola vez con la última emisión de cada observable de entrada, pero únicamente cuando todos completan. Este comportamiento la convierte en una herramienta precisa para coordinar operaciones finitas, como peticiones HTTP simultáneas.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los observables pasados a &lt;code&gt;forkJoin&lt;/code&gt; deben ser finitos. Si alguno nunca completa, &lt;code&gt;forkJoin&lt;/code&gt; nunca emitirá resultado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El diagrama muestra que la salida aparece al final, cuando todas las fuentes han completado y existe un último valor para cada una.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-forkjoin_hu_21713f02bc2dcb9.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Modo de uso:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;forkJoin&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;letras$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3500&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// forkJoin(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// numeros$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// intervalo$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// letras$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// ).subscribe(console.log);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// forkJoin(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// numeros$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// intervalo$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// letras$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// ).subscribe(resp =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(&amp;#39;numeros&amp;#39;, resp[0]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(&amp;#39;intervalo&amp;#39;, resp[1]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(&amp;#39;letras&amp;#39;, resp[2]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// forkJoin({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// numeros$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// intervalo$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// letras$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// }).subscribe(resp =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(resp);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;forkJoin&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;numeros$&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;int&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;intervalo$&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;letras$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;resp&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;resp&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La forma con objeto es especialmente práctica porque conserva nombres semánticos en la respuesta. En lugar de depender de índices como &lt;code&gt;resp[0]&lt;/code&gt;, &lt;code&gt;resp[1]&lt;/code&gt; o &lt;code&gt;resp[2]&lt;/code&gt;, el consumidor trabaja con propiedades explícitas: &lt;code&gt;num&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt; y &lt;code&gt;let&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;El uso más común de &lt;code&gt;forkJoin&lt;/code&gt; aparece cuando haces peticiones AJAX simultáneas y necesitas continuar solo cuando todas han terminado correctamente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cómo-elegir-entre-concat-merge-combinelatest-y-forkjoin"&gt;Cómo elegir entre &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt; y &lt;code&gt;forkJoin&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Estos operadores pueden parecer similares porque todos combinan fuentes, pero su semántica de tiempo es distinta:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;concat&lt;/code&gt;&lt;/strong&gt; cuando el orden secuencial sea obligatorio y cada fuente deba completar antes de iniciar la siguiente.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/strong&gt; cuando las fuentes sean independientes y quieras reaccionar a cualquiera de ellas tan pronto como emita.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt; cuando necesites calcular estado derivado a partir del último valor conocido de varias fuentes activas.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;forkJoin&lt;/code&gt;&lt;/strong&gt; cuando esperes observables finitos y solo necesites el resultado final de cada uno.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;startWith&lt;/code&gt;&lt;/strong&gt; y &lt;strong&gt;&lt;code&gt;endWith&lt;/code&gt;&lt;/strong&gt; para insertar emisiones de inicio o cierre dentro de un pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Esta elección tiene impacto directo en latencia, orden de ejecución y condiciones de completado. En sistemas reactivos, estos detalles definen si el flujo se mantiene responsivo o si queda bloqueado esperando una emisión que nunca llega.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Combinar observables RxJS requiere distinguir entre concurrencia, secuencialidad y sincronización de valores. &lt;code&gt;concat&lt;/code&gt; serializa fuentes, &lt;code&gt;merge&lt;/code&gt; las mezcla, &lt;code&gt;combineLatest&lt;/code&gt; deriva estado desde los últimos valores y &lt;code&gt;forkJoin&lt;/code&gt; espera resultados finales de observables finitos.&lt;/p&gt;
&lt;p&gt;Dominar estas diferencias permite diseñar pipelines más predecibles y expresivos. En el siguiente artículo aplicaremos estos conceptos al trabajo con peticiones AJAX, donde &lt;code&gt;forkJoin&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt; y otros operadores empiezan a interactuar con latencia real de red y manejo de errores.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores no tan comunes</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-no-tan-comunes-rxjs/</link><pubDate>Sun, 07 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-no-tan-comunes-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores rxjs menos frecuentes como take, first, takeWhile, takeUntil, skip, distinct y distinctUntilChanged.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#take-limitar-emisiones-de-un-observable"&gt;&lt;code&gt;take&lt;/code&gt;: limitar emisiones de un Observable&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#first-tomar-la-primera-emisión-o-la-primera-que-cumpla-una-condición"&gt;&lt;code&gt;first&lt;/code&gt;: tomar la primera emisión o la primera que cumpla una condición&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#first-con-predicado"&gt;&lt;code&gt;first&lt;/code&gt; con predicado&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#takewhile-emitir-mientras-se-mantenga-una-condición"&gt;&lt;code&gt;takeWhile&lt;/code&gt;: emitir mientras se mantenga una condición&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#takeuntil-cancelar-un-flujo-con-otro-observable"&gt;&lt;code&gt;takeUntil&lt;/code&gt;: cancelar un flujo con otro Observable&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#skip-omitir-emisiones-iniciales"&gt;&lt;code&gt;skip&lt;/code&gt;: omitir emisiones iniciales&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#distinct-eliminar-valores-repetidos-globalmente"&gt;&lt;code&gt;distinct&lt;/code&gt;: eliminar valores repetidos globalmente&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#distinct-con-selector-para-objetos"&gt;&lt;code&gt;distinct&lt;/code&gt; con selector para objetos&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#distinctuntilchanged-evitar-repeticiones-consecutivas"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt;: evitar repeticiones consecutivas&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#distinctuntilchanged-con-comparador"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt; con comparador&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#distinctuntilkeychanged-comparación-consecutiva-por-propiedad"&gt;&lt;code&gt;distinctUntilKeyChanged&lt;/code&gt;: comparación consecutiva por propiedad&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En flujos reactivos de interfaz, temporizadores o eventos del DOM, no siempre necesitas transformar cada emisión. Con frecuencia el problema operativo consiste en limitar una suscripción, cancelar un &lt;code&gt;Observable&lt;/code&gt; ante una señal externa o eliminar emisiones repetidas. Estos &lt;strong&gt;operadores RxJS&lt;/strong&gt; resuelven ese tipo de control sin introducir estado mutable adicional ni lógica imperativa alrededor de la suscripción.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de revisar &lt;a href="https://blog.dacadev.com/typescript/operadores-de-transformacion-rxjs/"



 


&gt;operadores de transformación&lt;/a&gt; y aquí analizaremos &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;takeWhile&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;, &lt;code&gt;distinct&lt;/code&gt;, &lt;code&gt;distinctUntilChanged&lt;/code&gt; y &lt;code&gt;distinctUntilKeyChanged&lt;/code&gt;. El siguiente artículo aborda los &lt;a href="https://blog.dacadev.com/typescript/operadores-combinacion-observables/"



 


&gt;operadores de combinación&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La referencia formal de estos operadores está en la documentación oficial de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt; y en el modelo conceptual de &lt;a href="https://reactivex.io"




 target="_blank"
 


&gt;ReactiveX&lt;/a&gt;. En este artículo nos concentraremos en su comportamiento práctico, especialmente en cuándo completan el flujo y cómo comparan valores.&lt;/p&gt;
&lt;h2 id="take-limitar-emisiones-de-un-observable"&gt;&lt;code&gt;take&lt;/code&gt;: limitar emisiones de un Observable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;take&lt;/code&gt; permite definir cuántas emisiones del &lt;code&gt;Observable&lt;/code&gt; fuente queremos recibir. Una vez alcanza ese límite, el operador completa la cadena y cancela la suscripción aguas arriba.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-take_hu_18c316156fc7352b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este patrón es útil cuando el consumidor solo necesita una muestra finita de un flujo potencialmente largo, como los primeros eventos, los primeros valores de un intervalo o una respuesta inicial.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El &lt;code&gt;tap&lt;/code&gt; se ejecuta solo para los valores que alcanzan la suscripción antes de que &lt;code&gt;take(3)&lt;/code&gt; complete el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-take_hu_acbd9bad5d1f147f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;take&lt;/code&gt; es una forma declarativa de evitar suscripciones más largas de lo necesario. En flujos infinitos como &lt;code&gt;interval&lt;/code&gt;, puede prevenir fugas si el ciclo de vida esperado es finito.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="first-tomar-la-primera-emisión-o-la-primera-que-cumpla-una-condición"&gt;&lt;code&gt;first&lt;/code&gt;: tomar la primera emisión o la primera que cumpla una condición&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;first&lt;/code&gt; obtiene la primera emisión del &lt;code&gt;Observable&lt;/code&gt; y completa la suscripción. Su caso básico se parece a &lt;code&gt;take(1)&lt;/code&gt;, pero también acepta un predicado para esperar la primera emisión que cumpla una condición.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-first_hu_b57c6c3a31077d9a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;first&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;first&lt;/span&gt;()).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Después del primer clic, el flujo completa y deja de escuchar nuevos eventos.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-first_hu_7c4360a367784e09.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="first-con-predicado"&gt;&lt;code&gt;first&lt;/code&gt; con predicado&lt;/h3&gt;
&lt;p&gt;Cuando &lt;code&gt;first&lt;/code&gt; recibe un predicado, ignora las emisiones previas hasta encontrar la primera que devuelva &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;first&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap&amp;#34;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;first&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;clientY&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;150&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El &lt;code&gt;tap&lt;/code&gt; confirma que el flujo sigue recibiendo clics, pero &lt;code&gt;first&lt;/code&gt; solo emite cuando la coordenada &lt;code&gt;clientY&lt;/code&gt; cumple la condición.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-first-predicate_hu_dd483944bae9057f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si la fuente completa sin que el predicado de &lt;code&gt;first&lt;/code&gt; se cumpla, RxJS puede emitir un error &lt;code&gt;EmptyError&lt;/code&gt;. Considera un valor por defecto o un operador alternativo cuando ese escenario sea válido.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="takewhile-emitir-mientras-se-mantenga-una-condición"&gt;&lt;code&gt;takeWhile&lt;/code&gt;: emitir mientras se mantenga una condición&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;takeWhile&lt;/code&gt; mantiene la suscripción activa mientras el predicado devuelva &lt;code&gt;true&lt;/code&gt;. En cuanto una emisión no cumple la condición, el operador completa el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-takewhile_hu_e42f671167cc2913.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En este ejemplo tomamos clics mientras la coordenada &lt;code&gt;y&lt;/code&gt; sea menor o igual a &lt;code&gt;150&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;takeWhile&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;takeWhile&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;150&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;coords&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;coords&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El segundo argumento, conocido como bandera &lt;strong&gt;inclusive&lt;/strong&gt;, indica si la emisión que rompe la condición también debe enviarse al suscriptor. Por defecto es &lt;code&gt;false&lt;/code&gt;; con &lt;code&gt;true&lt;/code&gt;, el valor que provoca el cierre se conserva.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-takewhile-inclusive_hu_e080f0a7ac2ad474.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;takeWhile&lt;/code&gt; modela límites basados en datos. Es diferente de &lt;code&gt;filter&lt;/code&gt;: &lt;code&gt;filter&lt;/code&gt; descarta valores y continúa; &lt;code&gt;takeWhile&lt;/code&gt; completa el flujo cuando la condición deja de cumplirse.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="takeuntil-cancelar-un-flujo-con-otro-observable"&gt;&lt;code&gt;takeUntil&lt;/code&gt;: cancelar un flujo con otro Observable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;takeUntil&lt;/code&gt; recibe un segundo &lt;code&gt;Observable&lt;/code&gt;, llamado normalmente &lt;code&gt;notifier&lt;/code&gt;. El flujo principal emite hasta que ese &lt;code&gt;notifier&lt;/code&gt; produce su primera emisión; en ese momento la cadena completa.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-takeuntil_hu_cdc0acc3e1676e92.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este patrón es común para cancelar intervalos, peticiones, listeners o cualquier proceso reactivo asociado al ciclo de vida de un componente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;boton&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;button&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;innerHTML&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Detener timing&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;body&amp;#34;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;append&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;)).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El contador sigue emitiendo cada segundo hasta que el botón produce un evento &lt;code&gt;click&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-takeuntil_hu_b86b54f77e79792e.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;En aplicaciones con componentes, &lt;code&gt;takeUntil&lt;/code&gt; suele conectarse a una señal de destrucción para liberar recursos y cerrar suscripciones de forma predecible.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="skip-omitir-emisiones-iniciales"&gt;&lt;code&gt;skip&lt;/code&gt;: omitir emisiones iniciales&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;skip&lt;/code&gt; ignora las primeras &lt;code&gt;n&lt;/code&gt; emisiones del &lt;code&gt;Observable&lt;/code&gt; fuente y deja pasar las posteriores. Es útil cuando las primeras señales representan inicialización, ruido operativo o eventos que no deben activar la lógica principal.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-skip_hu_34ae533aa471be84.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Aplicado al ejemplo anterior, podemos exigir varios clics antes de cancelar el contador. Con &lt;code&gt;skip(2)&lt;/code&gt;, el tercer clic es el primero que llega a &lt;code&gt;takeUntil&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;skip&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;boton&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;button&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;innerHTML&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Detener timing&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;body&amp;#34;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;append&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap-antes&amp;#34;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;skip&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap-despues&amp;#34;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;)).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La salida muestra que los primeros clics existen, pero no cruzan la frontera marcada por &lt;code&gt;skip&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-skip_hu_47b321fbdd1deba4.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h2 id="distinct-eliminar-valores-repetidos-globalmente"&gt;&lt;code&gt;distinct&lt;/code&gt;: eliminar valores repetidos globalmente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;distinct&lt;/code&gt; evita que el flujo emita valores ya observados previamente. La comparación base usa igualdad estricta (&lt;code&gt;===&lt;/code&gt;), por lo que tipo y valor deben coincidir.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-distinct_hu_c01e49d9695a2ef6.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt;()).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El operador conserva una memoria interna de valores ya emitidos y descarta repeticiones posteriores.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinct_hu_936aafc688e819b5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="distinct-con-selector-para-objetos"&gt;&lt;code&gt;distinct&lt;/code&gt; con selector para objetos&lt;/h3&gt;
&lt;p&gt;Con objetos, dos instancias con la misma estructura no son iguales por referencia. Para resolverlo, &lt;code&gt;distinct&lt;/code&gt; acepta un selector que define la clave de comparación.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso la unicidad se calcula por &lt;code&gt;nombre&lt;/code&gt;, no por referencia del objeto.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinct-selector_hu_e2d36d92979adb21.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;distinct&lt;/code&gt; mantiene un registro de claves ya vistas. En flujos largos o infinitos, evalúa el impacto en memoria o usa una estrategia con cierre explícito.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="distinctuntilchanged-evitar-repeticiones-consecutivas"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt;: evitar repeticiones consecutivas&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt; compara cada emisión con la emisión inmediatamente anterior. Solo descarta duplicados consecutivos; si un valor reaparece más adelante después de otro valor distinto, puede emitirse de nuevo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-distinctuntilchanged_hu_910145903f00acd.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La igualdad por defecto también usa &lt;code&gt;===&lt;/code&gt;; por eso &lt;code&gt;1&lt;/code&gt; y &lt;code&gt;&amp;quot;1&amp;quot;&lt;/code&gt; no se consideran duplicados.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinctuntilchanged_hu_c13ce3b955e241eb.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="distinctuntilchanged-con-comparador"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt; con comparador&lt;/h3&gt;
&lt;p&gt;Para objetos, el comparador recibe el valor anterior y el actual. Debe retornar &lt;code&gt;true&lt;/code&gt; cuando ambos se consideran equivalentes y, por tanto, el valor actual debe omitirse.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;anterior&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;actual&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;anterior&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#e06c75"&gt;actual&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El flujo descarta únicamente los personajes consecutivos con el mismo &lt;code&gt;nombre&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinctuntilchanged-comparator_hu_f501dff0424ef24d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h2 id="distinctuntilkeychanged-comparación-consecutiva-por-propiedad"&gt;&lt;code&gt;distinctUntilKeyChanged&lt;/code&gt;: comparación consecutiva por propiedad&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;distinctUntilKeyChanged&lt;/code&gt; aplica la misma idea de &lt;code&gt;distinctUntilChanged&lt;/code&gt;, pero optimizada para objetos cuando la comparación depende de una propiedad concreta.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-distinctuntilkeychanged_hu_502038a9e4c7fbd7.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilKeyChanged&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinctUntilKeyChanged&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;nombre&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La intención queda más explícita que con un comparador manual cuando solo necesitas evaluar una clave.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinctuntilkeychanged_hu_a313d9c96362d79c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Estos operadores no son secundarios; resuelven decisiones críticas de ciclo de vida, cancelación y deduplicación en flujos reactivos. &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;takeWhile&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt; y &lt;code&gt;skip&lt;/code&gt; controlan cuántas emisiones llegan al consumidor y cuándo termina la suscripción. &lt;code&gt;distinct&lt;/code&gt;, &lt;code&gt;distinctUntilChanged&lt;/code&gt; y &lt;code&gt;distinctUntilKeyChanged&lt;/code&gt; controlan repetición y semántica de igualdad.&lt;/p&gt;
&lt;p&gt;La regla práctica es seleccionar el operador según el límite que necesitas expresar: cantidad, condición, señal externa, emisiones iniciales o duplicados. Esa precisión mantiene tus pipelines de RxJS más declarativos, auditables y fáciles de mantener.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores de transformación</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-de-transformacion-rxjs/</link><pubDate>Fri, 05 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-de-transformacion-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores de transformación RxJS para aplanar flujos con mergeAll, mergeMap, switchMap, concatMap y exhaustMap.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#mergeall-aplanar-observables-internos-con-concurrencia"&gt;&lt;code&gt;mergeAll&lt;/code&gt;: aplanar observables internos con concurrencia&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#mergemap-transformar-y-mezclar-con-concurrencia-completa"&gt;&lt;code&gt;mergeMap&lt;/code&gt;: transformar y mezclar con concurrencia completa&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#switchmap-cancelar-lo-anterior-y-conservar-lo-más-reciente"&gt;&lt;code&gt;switchMap&lt;/code&gt;: cancelar lo anterior y conservar lo más reciente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#concatmap-preservar-orden-y-ejecutar-de-forma-secuencial"&gt;&lt;code&gt;concatMap&lt;/code&gt;: preservar orden y ejecutar de forma secuencial&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#exhaustmap-ignorar-nuevas-emisiones-mientras-hay-trabajo-activo"&gt;&lt;code&gt;exhaustMap&lt;/code&gt;: ignorar nuevas emisiones mientras hay trabajo activo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuándo-elegir-cada-operador-de-transformación-rxjs"&gt;Cuándo elegir cada operador de transformación RxJS&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando una aplicación combina eventos de UI, peticiones HTTP y procesos asíncronos, el flujo deja de ser una secuencia plana de valores y empieza a producir &lt;strong&gt;observables internos&lt;/strong&gt;. Los &lt;strong&gt;operadores de transformación RxJS&lt;/strong&gt; resuelven ese punto crítico: convierten un observable de observables en un flujo consumible, controlando concurrencia, cancelación, orden y exclusión de trabajo duplicado.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar &lt;a href="https://blog.dacadev.com/typescript/operadores-de-tiempo-rxjs/"



 


&gt;Operadores de tiempo&lt;/a&gt; y aquí abordaremos &lt;code&gt;mergeAll&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;concatMap&lt;/code&gt; y &lt;code&gt;exhaustMap&lt;/code&gt;; después continuaremos con &lt;a href="https://blog.dacadev.com/typescript/operadores-no-tan-comunes-rxjs/"



 


&gt;Operadores no tan comunes&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La documentación oficial de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt; describe estos operadores como herramientas para trabajar con &lt;strong&gt;higher-order observables&lt;/strong&gt;: observables cuyas emisiones son, a su vez, otros observables. En términos prácticos, aparecen cada vez que un evento dispara trabajo asíncrono: una búsqueda, un guardado, una carga incremental o una operación remota.&lt;/p&gt;
&lt;p&gt;La diferencia entre estos operadores no es cosmética. Elegir uno u otro define cómo se comporta el sistema ante emisiones rápidas: si ejecuta todo en paralelo, cancela lo anterior, serializa las tareas o ignora nuevos eventos mientras una operación sigue activa.&lt;/p&gt;
&lt;h2 id="mergeall-aplanar-observables-internos-con-concurrencia"&gt;&lt;code&gt;mergeAll&lt;/code&gt;: aplanar observables internos con concurrencia&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mergeAll&lt;/code&gt; trabaja sobre un observable que emite observables. Se suscribe a cada observable interno y reemite sus valores en el flujo resultante. El resultado se completa únicamente cuando el observable exterior se completa y todos los observables internos activos también han completado.&lt;/p&gt;
&lt;p&gt;Este operador es útil cuando ya tienes construidos los observables internos y solo necesitas aplanarlos. Por ejemplo, una capa previa puede generar varias operaciones independientes: guardar un borrador, registrar auditoría y sincronizar métricas. Si ninguna depende del resultado de la otra, &lt;code&gt;mergeAll&lt;/code&gt; permite ejecutarlas con concurrencia.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-mergeall_hu_994d656b4b603393.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En el diagrama, cada emisión del flujo superior representa un observable interno. &lt;code&gt;mergeAll&lt;/code&gt; mezcla sus emisiones conforme llegan, sin preservar necesariamente el orden original entre observables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mergeAll&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saveDraft$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;draft saved&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sendAudit$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;100&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;audit sent&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;syncMetrics$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;200&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;metrics synced&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;([&lt;span style="color:#e06c75"&gt;saveDraft$&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;sendAudit$&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;syncMetrics$&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mergeAll&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// audit sent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// metrics synced
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// draft saved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El ejemplo muestra un comportamiento clave: el orden de salida depende del tiempo de finalización de cada observable interno. Si necesitas preservar orden estricto, &lt;code&gt;mergeAll&lt;/code&gt; no es la herramienta adecuada; &lt;code&gt;concatMap&lt;/code&gt; encaja mejor en ese caso.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;mergeAll&lt;/code&gt; cuando ya tienes observables internos construidos y deseas aplanarlos. Si primero necesitas transformar cada valor del flujo exterior en un observable, normalmente &lt;code&gt;mergeMap&lt;/code&gt; expresa mejor la intención.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="mergemap-transformar-y-mezclar-con-concurrencia-completa"&gt;&lt;code&gt;mergeMap&lt;/code&gt;: transformar y mezclar con concurrencia completa&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mergeMap&lt;/code&gt; combina dos pasos: transforma cada emisión del observable fuente en un observable interno y luego mezcla las emisiones de todos esos observables. Conceptualmente equivale a aplicar &lt;code&gt;map&lt;/code&gt; para crear observables y después &lt;code&gt;mergeAll&lt;/code&gt; para aplanarlos.&lt;/p&gt;
&lt;p&gt;Su semántica favorece la concurrencia. Cada emisión entrante dispara una nueva suscripción interna, y las suscripciones anteriores permanecen activas hasta completar. Esto lo hace adecuado para operaciones independientes donde cancelar trabajo previo sería incorrecto, como escrituras, telemetría, cargas paralelas o procesamiento de elementos sin dependencia de orden.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-mergemap_hu_8f747c544c480b92.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mergeMap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;User&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;userIds&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;101&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;102&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;103&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;104&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;userIds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mergeMap&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;`/api/users/&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#d19a66"&gt;4&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// límite de concurrencia
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Usuario cargado:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aunque &lt;code&gt;mergeMap&lt;/code&gt; suele asociarse con “concurrencia completa”, RxJS permite limitar esa concurrencia con el segundo argumento. Este detalle es importante cuando el flujo fuente puede emitir muchos valores y cada valor dispara trabajo costoso, como peticiones HTTP o acceso a recursos externos.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;mergeMap&lt;/code&gt; no cancela observables internos anteriores. Si el flujo fuente emite más rápido de lo que los internos completan, puedes acumular trabajo concurrente y aumentar presión sobre red, memoria o servicios remotos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="switchmap-cancelar-lo-anterior-y-conservar-lo-más-reciente"&gt;&lt;code&gt;switchMap&lt;/code&gt;: cancelar lo anterior y conservar lo más reciente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;switchMap&lt;/code&gt; también transforma cada emisión en un observable interno, pero mantiene activa solo la suscripción más reciente. Cuando llega una nueva emisión desde el observable fuente, cancela la suscripción interna anterior y se cambia al nuevo observable.&lt;/p&gt;
&lt;p&gt;Esta semántica es ideal para escenarios donde el resultado anterior pierde relevancia al aparecer una entrada más nueva. El caso clásico es un typeahead o autocomplete: si el usuario escribe &lt;code&gt;rea&lt;/code&gt; y luego &lt;code&gt;react&lt;/code&gt;, la respuesta de &lt;code&gt;rea&lt;/code&gt; ya no debe actualizar la UI aunque llegue después.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-switchmap_hu_113998a3529e5491.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;SearchResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;title&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#search&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;term&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;term&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;length&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#56b6c2"&gt;?&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;SearchResult&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#98c379"&gt;`/api/search?q=&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;encodeURIComponent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;term&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;results&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Resultados vigentes:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;results&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El valor operativo de &lt;code&gt;switchMap&lt;/code&gt; está en la cancelación. En Angular, por ejemplo, cancelar la suscripción a una petición HTTP puede abortar la solicitud subyacente; en otros contextos, al menos evita que respuestas obsoletas lleguen al consumidor final.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Elige &lt;code&gt;switchMap&lt;/code&gt; cuando el sistema debe representar el estado más reciente: búsquedas, filtros dinámicos, navegación dependiente de parámetros o recarga de datos por selección activa.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="concatmap-preservar-orden-y-ejecutar-de-forma-secuencial"&gt;&lt;code&gt;concatMap&lt;/code&gt;: preservar orden y ejecutar de forma secuencial&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;concatMap&lt;/code&gt; transforma cada emisión en un observable interno, pero no se suscribe al siguiente hasta que el observable interno actual completa. En lugar de mezclar resultados, crea una cola: procesa una tarea, espera su finalización y continúa con la siguiente.&lt;/p&gt;
&lt;p&gt;Este comportamiento es crucial cuando el orden importa o cuando el backend espera operaciones serializadas. Casos típicos incluyen guardar cambios en secuencia, ejecutar comandos de dominio, procesar pasos de onboarding o enviar eventos que deben respetar causalidad.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-concatmap_hu_6f93690790aa1f0e.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;concatMap&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;OrderCommand&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;validated&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;charged&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;confirmed&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;commands&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;OrderCommand&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;validated&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;charged&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;confirmed&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;commands&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;concatMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;command&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;post&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;/api/orders/commands&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;command&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Comando procesado en orden&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La principal ventaja de &lt;code&gt;concatMap&lt;/code&gt; es la predictibilidad. La desventaja es la latencia acumulada: si cada operación tarda 500 ms y tienes diez elementos, el flujo tardará al menos cinco segundos en procesar la cola completa.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;concatMap&lt;/code&gt; puede acumular una cola grande si la fuente emite más rápido de lo que completan los observables internos. Evalúa backpressure, límites de entrada o estrategias de descarte si el volumen no está controlado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="exhaustmap-ignorar-nuevas-emisiones-mientras-hay-trabajo-activo"&gt;&lt;code&gt;exhaustMap&lt;/code&gt;: ignorar nuevas emisiones mientras hay trabajo activo&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;exhaustMap&lt;/code&gt; transforma una emisión en un observable interno y, mientras ese observable está activo, ignora todas las emisiones posteriores del observable fuente. Cuando el observable interno completa, el operador queda listo para aceptar una nueva emisión.&lt;/p&gt;
&lt;p&gt;Este patrón es útil cuando una operación no debe ejecutarse dos veces en paralelo. Formularios de login, botones de pago, acciones de envío y procesos idempotentes costosos suelen beneficiarse de esta semántica: el primer evento inicia el trabajo y los siguientes clics se descartan hasta terminar.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-exhaustmap_hu_b8ae1a19035b9470.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;exhaustMap&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;PaymentResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;transactionId&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;payButton&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLButtonElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#pay&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;payload&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;payButton&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;exhaustMap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;post&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PaymentResult&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;/api/payments&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;payload&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Pago procesado:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;transactionId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A diferencia de &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;exhaustMap&lt;/code&gt; no cancela el trabajo activo. A diferencia de &lt;code&gt;mergeMap&lt;/code&gt;, tampoco crea trabajo adicional. Su contrato es deliberadamente estricto: “ignorar mientras esté ocupado”.&lt;/p&gt;
&lt;h2 id="cuándo-elegir-cada-operador-de-transformación-rxjs"&gt;Cuándo elegir cada operador de transformación RxJS&lt;/h2&gt;
&lt;p&gt;La elección correcta depende de la política de concurrencia que necesita el sistema, no solo de la forma del código.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usa &lt;code&gt;mergeAll&lt;/code&gt; cuando recibes observables internos ya creados y quieres mezclarlos.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;mergeMap&lt;/code&gt; cuando cada emisión dispara trabajo independiente y aceptas concurrencia.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;switchMap&lt;/code&gt; cuando solo importa el resultado más reciente y conviene cancelar lo anterior.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;concatMap&lt;/code&gt; cuando necesitas orden, serialización o consistencia secuencial.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;exhaustMap&lt;/code&gt; cuando una operación activa debe bloquear nuevas emisiones hasta completar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Una regla práctica es observar qué debería ocurrir si llegan tres emisiones rápidas. Si las tres deben ejecutarse, &lt;code&gt;mergeMap&lt;/code&gt;. Si solo la última importa, &lt;code&gt;switchMap&lt;/code&gt;. Si las tres deben ejecutarse en orden, &lt;code&gt;concatMap&lt;/code&gt;. Si solo la primera debe ejecutarse y las demás deben ignorarse mientras está activa, &lt;code&gt;exhaustMap&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los operadores de transformación RxJS definen cómo se conectan eventos de alto nivel con trabajo asíncrono real. &lt;code&gt;mergeAll&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;concatMap&lt;/code&gt; y &lt;code&gt;exhaustMap&lt;/code&gt; no son variantes intercambiables; cada uno codifica una política distinta de concurrencia, cancelación y orden.&lt;/p&gt;
&lt;p&gt;Al diseñar flujos reactivos en TypeScript, conviene elegir el operador a partir del contrato del dominio. Esa decisión reduce condiciones de carrera, evita respuestas obsoletas, controla presión sobre recursos externos y hace que la intención del flujo sea explícita para el equipo.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores de tiempo</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-de-tiempo-rxjs/</link><pubDate>Wed, 03 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-de-tiempo-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores de tiempo RxJS como debounceTime, throttleTime, sampleTime, sample y auditTime para controlar emisiones en streams.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/time-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#por-qué-usar-operadores-de-tiempo-rxjs"&gt;Por qué usar operadores de tiempo RxJS&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#debouncetime-esperar-silencio-antes-de-emitir"&gt;&lt;code&gt;debounceTime&lt;/code&gt;: esperar silencio antes de emitir&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#throttletime-limitar-la-frecuencia-de-emisión"&gt;&lt;code&gt;throttleTime&lt;/code&gt;: limitar la frecuencia de emisión&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#configuración-leading-y-trailing"&gt;Configuración &lt;code&gt;leading&lt;/code&gt; y &lt;code&gt;trailing&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#sampletime-tomar-snapshots-periódicos-del-último-valor"&gt;&lt;code&gt;sampleTime&lt;/code&gt;: tomar snapshots periódicos del último valor&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#sample-emitir-cuando-otro-observable-lo-indique"&gt;&lt;code&gt;sample&lt;/code&gt;: emitir cuando otro observable lo indique&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#audittime-emitir-el-último-valor-al-cerrar-una-ventana"&gt;&lt;code&gt;auditTime&lt;/code&gt;: emitir el último valor al cerrar una ventana&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#comparación-rápida-de-operadores-de-tiempo"&gt;Comparación rápida de operadores de tiempo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando un flujo de eventos del navegador emite con demasiada frecuencia, la lógica de aplicación puede terminar procesando ruido en lugar de señales útiles. Los &lt;strong&gt;operadores de tiempo RxJS&lt;/strong&gt; permiten controlar esa presión temporal en escenarios como búsquedas con autocompletado, eventos de &lt;code&gt;scroll&lt;/code&gt;, clics repetidos, métricas periódicas o capturas de estado. En este artículo analizaremos &lt;code&gt;debounceTime&lt;/code&gt;, &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;sampleTime&lt;/code&gt;, &lt;code&gt;sample&lt;/code&gt; y &lt;code&gt;auditTime&lt;/code&gt; con ejemplos en TypeScript y diagramas de canicas.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de &lt;a href="https://blog.dacadev.com/typescript/operadores-basicos-rxjs/"



 


&gt;Operadores básicos&lt;/a&gt; y continuaremos con &lt;a href="https://blog.dacadev.com/typescript/operadores-de-transformacion-rxjs/"



 


&gt;Operadores de transformación&lt;/a&gt;. Aquí abordaremos cómo regular emisiones en el tiempo sin acoplar la lógica de negocio a temporizadores manuales.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="por-qué-usar-operadores-de-tiempo-rxjs"&gt;Por qué usar operadores de tiempo RxJS&lt;/h2&gt;
&lt;p&gt;En &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;, un &lt;strong&gt;observable&lt;/strong&gt; puede emitir valores con una cadencia muy superior a la capacidad real de procesamiento de la interfaz o del backend. Un &lt;code&gt;keyup&lt;/code&gt; puede dispararse en cada tecla, un &lt;code&gt;mousemove&lt;/code&gt; puede emitir decenas de veces por segundo y un botón puede recibir clics duplicados antes de que termine una operación asíncrona. Sin control temporal, el sistema incrementa latencia, consumo de CPU y llamadas innecesarias.&lt;/p&gt;
&lt;p&gt;Los operadores de tiempo resuelven este problema dentro del pipeline reactivo. En lugar de mezclar &lt;code&gt;setTimeout&lt;/code&gt;, flags mutables y cancelaciones manuales, expresamos la política de emisión con operadores declarativos. Esto mantiene la suscripción enfocada en consumir valores ya estabilizados, muestreados o limitados.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;En ReactiveX, estos operadores suelen representarse con diagramas de canicas porque el comportamiento depende tanto del valor como del instante de emisión. Los diagramas del artículo provienen de la nota original y se conservan como referencia visual.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="debouncetime-esperar-silencio-antes-de-emitir"&gt;&lt;code&gt;debounceTime&lt;/code&gt;: esperar silencio antes de emitir&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;debounceTime&lt;/code&gt; emite el último valor del observable fuente solo cuando transcurre un intervalo sin nuevas emisiones. Si llega otro valor antes de que venza el temporizador, el valor anterior se descarta y el conteo vuelve a empezar. Esta semántica es especialmente útil para entradas de texto, filtros de búsqueda y eventos donde interesa la intención final del usuario, no cada evento intermedio.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-debouncetime_hu_df49dfb632f6cdd2.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Consideremos un flujo de clics. La suscripción recibirá un evento únicamente si pasan tres segundos sin otro clic adicional:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3000&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En formularios, &lt;code&gt;debounceTime&lt;/code&gt; suele combinarse con &lt;code&gt;distinctUntilChanged&lt;/code&gt; para evitar trabajo duplicado cuando el valor estabilizado no cambió realmente. La nota original usa &lt;code&gt;pluck('target', 'value')&lt;/code&gt;; funciona como referencia histórica, pero &lt;code&gt;pluck&lt;/code&gt; está deprecado en RxJS 7. La alternativa moderna es &lt;code&gt;map&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;body&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1500&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;pluck&lt;/code&gt; aparece en muchos ejemplos clásicos de RxJS, pero está deprecado. Para código nuevo, usa &lt;code&gt;map&lt;/code&gt; y extrae explícitamente la propiedad requerida; el resultado es más tipado y más claro para TypeScript.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="throttletime-limitar-la-frecuencia-de-emisión"&gt;&lt;code&gt;throttleTime&lt;/code&gt;: limitar la frecuencia de emisión&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;throttleTime&lt;/code&gt; permite emitir un valor y luego ignorar nuevas emisiones durante una ventana temporal. Por defecto, emite el primer valor de cada ventana y descarta los valores posteriores hasta que el intervalo termina. Es una estrategia útil cuando necesitas una respuesta inmediata, pero quieres proteger el sistema contra ráfagas de eventos.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-throttletime_hu_c578b31ad733fd0c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El siguiente ejemplo procesa como máximo un valor de teclado cada &lt;code&gt;1500&lt;/code&gt; milisegundos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;body&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1500&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="configuración-leading-y-trailing"&gt;Configuración &lt;code&gt;leading&lt;/code&gt; y &lt;code&gt;trailing&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;La configuración avanzada de &lt;code&gt;throttleTime&lt;/code&gt; permite decidir si se emite el valor inicial de la ventana (&lt;code&gt;leading&lt;/code&gt;) y/o el último valor capturado durante esa ventana (&lt;code&gt;trailing&lt;/code&gt;). Esta configuración es importante cuando necesitas respuesta inmediata y, además, preservar el estado final de una ráfaga.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;body&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1500&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;leading&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;trailing&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/console-throttletime-leading-trailing_hu_cf13178f161f0ddf.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Con &lt;code&gt;leading: true&lt;/code&gt;, la primera emisión sale de inmediato. Con &lt;code&gt;trailing: true&lt;/code&gt;, el último valor observado durante la ventana se emite al cerrar el intervalo. Esta combinación es adecuada para interacciones donde importa tanto la reacción inicial como el estado final.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;debounceTime&lt;/code&gt; cuando solo importa el valor estabilizado. Usa &lt;code&gt;throttleTime&lt;/code&gt; cuando necesitas una primera respuesta rápida y una frecuencia máxima controlada.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="sampletime-tomar-snapshots-periódicos-del-último-valor"&gt;&lt;code&gt;sampleTime&lt;/code&gt;: tomar snapshots periódicos del último valor&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sampleTime&lt;/code&gt; toma una muestra del último valor emitido por la fuente cada cierto intervalo. A diferencia de &lt;code&gt;throttleTime&lt;/code&gt;, el reloj no se inicia por una emisión del observable fuente; el operador usa un intervalo periódico. Si no hubo valores nuevos desde el último tick, no emite nada.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-sampletime_hu_69fc070df878c35.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El siguiente pipeline captura la última posición de clic cada dos segundos, siempre que haya ocurrido al menos un clic durante ese periodo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;sampleTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sampleTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esta estrategia encaja bien en telemetría, dashboards o cálculos de posición donde no necesitas procesar cada evento, sino observar el estado más reciente a una cadencia fija. También reduce el acoplamiento entre la frecuencia de entrada y la frecuencia de procesamiento.&lt;/p&gt;
&lt;h2 id="sample-emitir-cuando-otro-observable-lo-indique"&gt;&lt;code&gt;sample&lt;/code&gt;: emitir cuando otro observable lo indique&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sample&lt;/code&gt; generaliza la idea de muestreo: en lugar de usar un intervalo fijo, recibe un observable notificador. Cada vez que el notificador emite, &lt;code&gt;sample&lt;/code&gt; publica el último valor conocido de la fuente, si existe uno disponible desde la muestra anterior.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-sample_hu_aa6f1456817a5273.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En este ejemplo, &lt;code&gt;interval$&lt;/code&gt; genera valores cada &lt;code&gt;500&lt;/code&gt; milisegundos, pero solo se emite el último valor cuando ocurre un clic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;sample&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;sample&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sample&lt;/code&gt; es útil cuando un evento externo define el momento de lectura. Por ejemplo, puedes mantener un stream de estado interno y emitir snapshots solo cuando el usuario confirma una acción, cuando llega una señal de sincronización o cuando otro subsistema solicita una captura.&lt;/p&gt;
&lt;h2 id="audittime-emitir-el-último-valor-al-cerrar-una-ventana"&gt;&lt;code&gt;auditTime&lt;/code&gt;: emitir el último valor al cerrar una ventana&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;auditTime&lt;/code&gt; inicia una ventana temporal cuando recibe una emisión de la fuente. Durante esa ventana ignora las emisiones intermedias, pero conserva la última. Al finalizar el intervalo, emite ese último valor capturado.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-audittime_hu_4ee11ac40f69d025.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Su comportamiento resulta útil cuando el primer valor de una ráfaga no es tan relevante como el valor final dentro de una ventana de procesamiento. El siguiente ejemplo registra cada clic con &lt;code&gt;tap&lt;/code&gt;, transforma la posición y luego deja pasar el último valor cada dos segundos desde el inicio de cada ventana:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;auditTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;tap&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;auditTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/console-audittime_hu_24178ca659502169.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La diferencia práctica frente a &lt;code&gt;debounceTime&lt;/code&gt; es que &lt;code&gt;auditTime&lt;/code&gt; no espera silencio global para emitir. Si hay una ráfaga continua, seguirá emitiendo el último valor de cada ventana auditada. Frente a &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;auditTime&lt;/code&gt; se enfoca en el valor final de la ventana, no en el inicial.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;auditTime&lt;/code&gt; es una buena opción para flujos de alta frecuencia donde necesitas snapshots finales por ventana: movimientos de puntero, scroll, reflujo visual o mediciones periódicas derivadas de eventos continuos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="comparación-rápida-de-operadores-de-tiempo"&gt;Comparación rápida de operadores de tiempo&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Operador&lt;/th&gt;
 &lt;th&gt;Cuándo emite&lt;/th&gt;
 &lt;th&gt;Caso típico&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;debounceTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Cuando pasa un intervalo sin nuevas emisiones&lt;/td&gt;
 &lt;td&gt;Búsqueda después de que el usuario deja de escribir&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;throttleTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Al inicio de una ventana; opcionalmente también al final&lt;/td&gt;
 &lt;td&gt;Clics, scroll o resize con respuesta inmediata&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sampleTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;En ticks periódicos, si hay un valor nuevo&lt;/td&gt;
 &lt;td&gt;Telemetría o snapshots a cadencia fija&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sample&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Cuando emite otro observable notificador&lt;/td&gt;
 &lt;td&gt;Capturar estado bajo demanda&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;auditTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Al final de una ventana iniciada por la fuente&lt;/td&gt;
 &lt;td&gt;Emitir el último valor de una ráfaga temporal&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los operadores de tiempo RxJS permiten diseñar pipelines reactivos con políticas temporales explícitas. &lt;code&gt;debounceTime&lt;/code&gt; reduce ruido esperando estabilidad, &lt;code&gt;throttleTime&lt;/code&gt; limita frecuencia con respuesta inicial, &lt;code&gt;sampleTime&lt;/code&gt; toma snapshots periódicos, &lt;code&gt;sample&lt;/code&gt; delega el momento de lectura a otro observable y &lt;code&gt;auditTime&lt;/code&gt; conserva el último valor de una ventana.&lt;/p&gt;
&lt;p&gt;Elegir correctamente entre estos operadores evita temporizadores manuales, reduce estado mutable y mantiene el control de emisiones cerca del flujo que lo necesita. En el siguiente artículo de la serie abordaremos operadores de transformación para modificar la forma de los valores que viajan por el stream.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores básicos</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-basicos-rxjs/</link><pubDate>Mon, 01 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-basicos-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores rxjs esenciales como map, filter, tap, reduce y scan, y domina el operador pipe rxjs para transformar streams.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-son-los-operadores-rxjs-y-cómo-funciona-pipe"&gt;Qué son los operadores rxjs y cómo funciona &lt;code&gt;pipe&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#map-transformar-emisiones-con-map-filter-rxjs"&gt;&lt;code&gt;map&lt;/code&gt;: transformar emisiones con &lt;code&gt;map filter rxjs&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#pluck-extraer-propiedades-anidadas"&gt;&lt;code&gt;pluck&lt;/code&gt;: extraer propiedades anidadas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#mapto-reemplazar-cada-emisión-por-un-valor-constante"&gt;&lt;code&gt;mapTo&lt;/code&gt;: reemplazar cada emisión por un valor constante&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#filter-filtrar-emisiones-del-stream"&gt;&lt;code&gt;filter&lt;/code&gt;: filtrar emisiones del stream&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#encadenamiento-con-el-operador-pipe-rxjs"&gt;Encadenamiento con el operador pipe rxjs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tap-efectos-secundarios-sin-transformar-el-flujo"&gt;&lt;code&gt;tap&lt;/code&gt;: efectos secundarios sin transformar el flujo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#reduce-acumular-y-emitir-al-completar"&gt;&lt;code&gt;reduce&lt;/code&gt;: acumular y emitir al completar&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#scan-acumular-y-emitir-cada-estado-intermedio"&gt;&lt;code&gt;scan&lt;/code&gt;: acumular y emitir cada estado intermedio&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En una aplicación reactiva, el problema rara vez consiste solo en recibir eventos; el reto aparece al transformar, filtrar y acumular emisiones sin acoplar la lógica de negocio a cada suscripción. Los &lt;strong&gt;operadores rxjs&lt;/strong&gt; resuelven ese punto al permitir que un &lt;code&gt;Observable&lt;/code&gt; exponga un flujo derivado, más específico y más seguro para quien lo consume.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar &lt;a href="https://blog.dacadev.com/typescript/funciones-crear-observables/"



 


&gt;Funciones para crear Observables&lt;/a&gt; y aquí abordaremos &lt;code&gt;pipe&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;pluck&lt;/code&gt;, &lt;code&gt;mapTo&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, encadenamiento, &lt;code&gt;tap&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt; y &lt;code&gt;scan&lt;/code&gt;. El siguiente paso será estudiar &lt;a href="https://blog.dacadev.com/typescript/operadores-de-tiempo-rxjs/"



 


&gt;Operadores de tiempo&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="qué-son-los-operadores-rxjs-y-cómo-funciona-pipe"&gt;Qué son los operadores rxjs y cómo funciona &lt;code&gt;pipe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Un &lt;strong&gt;operador&lt;/strong&gt; es una función que recibe las emisiones de un &lt;code&gt;Observable&lt;/code&gt; y devuelve otro &lt;code&gt;Observable&lt;/code&gt; con un comportamiento derivado. Ese comportamiento puede transformar valores, filtrar emisiones, ejecutar efectos secundarios controlados o acumular estado a lo largo del stream.&lt;/p&gt;
&lt;p&gt;En RxJS, los operadores se aplican con el método &lt;code&gt;pipe&lt;/code&gt;. Esta API permite declarar una cadena de procesamiento explícita, donde cada operador recibe la salida del anterior y entrega su resultado al siguiente. La documentación oficial de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt; describe este patrón como la base para componer flujos asincrónicos de manera declarativa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La suscripción no debería cargar con toda la lógica de transformación. En un diseño mantenible, &lt;code&gt;subscribe&lt;/code&gt; se reserva para consumir el resultado final, mientras que &lt;code&gt;pipe&lt;/code&gt; documenta la estrategia de procesamiento del flujo.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Mantén la lógica de transformación dentro de &lt;code&gt;pipe&lt;/code&gt;. Esto reduce acoplamiento, facilita pruebas unitarias sobre operadores y evita suscripciones con demasiada responsabilidad.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="map-transformar-emisiones-con-map-filter-rxjs"&gt;&lt;code&gt;map&lt;/code&gt;: transformar emisiones con &lt;code&gt;map filter rxjs&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;map&lt;/code&gt;&lt;/strong&gt; proyecta cada emisión del &lt;code&gt;Observable&lt;/code&gt; original hacia un nuevo valor. Es equivalente al concepto de proyección funcional: por cada entrada existe una salida, sin modificar el origen y sin alterar la cantidad de emisiones.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-map_hu_e00f6d1ff71d0bd5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En el diagrama de canicas, cada valor emitido pasa por una función de transformación y continúa en el stream resultante con una nueva representación. Esto permite convertir modelos, normalizar datos o derivar valores calculados antes de que lleguen a la suscripción.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;multiplied$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;source&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;multiplied$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;map&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;También puedes escribirlo de forma compacta cuando no necesitas conservar una referencia al &lt;code&gt;Observable&lt;/code&gt; intermedio:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado conserva el orden de las emisiones y aplica la función a cada valor individual.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-map_hu_e21585c67d7ecd41.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;map&lt;/code&gt; es una pieza central en pipelines donde necesitas convertir eventos del DOM, respuestas HTTP o estructuras de dominio en datos listos para la capa que los consume.&lt;/p&gt;
&lt;h2 id="pluck-extraer-propiedades-anidadas"&gt;&lt;code&gt;pluck&lt;/code&gt;: extraer propiedades anidadas&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;pluck&lt;/code&gt;&lt;/strong&gt; extrae propiedades de objetos emitidos por un &lt;code&gt;Observable&lt;/code&gt;. En notas y proyectos con RxJS más antiguos aparece con frecuencia para leer rutas como &lt;code&gt;target.baseURI&lt;/code&gt; dentro de un evento del DOM.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-pluck_hu_5426da1479087d60.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Un ejemplo clásico consiste en escuchar eventos &lt;code&gt;keyup&lt;/code&gt; y extraer una propiedad anidada del objeto &lt;code&gt;KeyboardEvent&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;target&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;baseURI&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;pluck&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al presionar una tecla, el &lt;code&gt;Observable&lt;/code&gt; original emite el evento completo, mientras que el stream derivado emite solo la propiedad seleccionada.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-pluck_hu_3b2445a8681576fe.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;pluck&lt;/code&gt; está deprecado en versiones modernas de RxJS. Prefiere &lt;code&gt;map&lt;/code&gt; con acceso explícito a propiedades, porque ofrece mejor tipado, autocompletado y refactorización segura.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La alternativa recomendada usa &lt;code&gt;map&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;instanceof&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Element&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;?&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;baseURI&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;baseURI&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="mapto-reemplazar-cada-emisión-por-un-valor-constante"&gt;&lt;code&gt;mapTo&lt;/code&gt;: reemplazar cada emisión por un valor constante&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;mapTo&lt;/code&gt;&lt;/strong&gt; transforma cualquier entrada en un valor constante. Es útil cuando el contenido de la emisión original no importa y solo necesitas representar una señal semántica, por ejemplo: “hubo interacción”, “se presionó una tecla” o “se completó un paso”.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-map-to_hu_8f3f642b0c00aa40.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyPressed$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Tecla presionada&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;keyPressed$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mapTo&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cada evento &lt;code&gt;keyup&lt;/code&gt; se reemplaza por la misma cadena.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-map-to_hu_cbac4f701b02c8cc.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En código moderno, también puedes usar &lt;code&gt;map(() =&amp;gt; valor)&lt;/code&gt; para lograr el mismo resultado y mantener consistencia con el resto de tus transformaciones.&lt;/p&gt;
&lt;h2 id="filter-filtrar-emisiones-del-stream"&gt;&lt;code&gt;filter&lt;/code&gt;: filtrar emisiones del stream&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/strong&gt; deja pasar únicamente las emisiones que cumplen un predicado. A diferencia de &lt;code&gt;map&lt;/code&gt;, este operador sí puede cambiar la cantidad de emisiones que recibe la suscripción, porque descarta los valores que no satisfacen la condición.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-filter_hu_1050d12e416827c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El callback de &lt;code&gt;filter&lt;/code&gt; recibe el valor emitido y el índice de la emisión. Esto permite aplicar reglas basadas en el contenido del valor o en su posición dentro del stream.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;index&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;index&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;%&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso, solo pasan los números impares.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-filter-numbers_hu_2e6f024c6af9ed48.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;filter&lt;/code&gt; también es útil con objetos de dominio. El siguiente ejemplo convierte un arreglo en un &lt;code&gt;Observable&lt;/code&gt; y deja pasar únicamente los personajes de tipo &lt;code&gt;heroe&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Batman&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Robin&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Joker&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;filter&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El stream resultante contiene solo los objetos que cumplen el predicado.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-filter-objects_hu_33a3b6d187cd0d2a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;filter&lt;/code&gt; no transforma el valor; controla si una emisión continúa o se descarta. Si necesitas modificar el valor después del filtrado, encadena un &lt;code&gt;map&lt;/code&gt; a continuación.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="encadenamiento-con-el-operador-pipe-rxjs"&gt;Encadenamiento con el operador pipe rxjs&lt;/h2&gt;
&lt;p&gt;El &lt;strong&gt;operador pipe rxjs&lt;/strong&gt; permite componer varios operadores en una secuencia legible. Cada paso debería tener una responsabilidad clara: extraer un dato, filtrar una condición, transformar un modelo o ejecutar un efecto secundario controlado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;enterKey$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;code&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Enter&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;enterKey$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;chain&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí el primer operador transforma &lt;code&gt;KeyboardEvent&lt;/code&gt; en &lt;code&gt;event.code&lt;/code&gt;, y el segundo operador deja pasar únicamente la tecla &lt;code&gt;Enter&lt;/code&gt;. La suscripción recibe un stream ya procesado, sin conocer el detalle del evento original del DOM.&lt;/p&gt;
&lt;p&gt;Esta composición es especialmente importante cuando el flujo crece. En lugar de acumular lógica imperativa dentro de callbacks, puedes expresar el pipeline de datos como una serie de transformaciones pequeñas y verificables.&lt;/p&gt;
&lt;h2 id="tap-efectos-secundarios-sin-transformar-el-flujo"&gt;&lt;code&gt;tap&lt;/code&gt;: efectos secundarios sin transformar el flujo&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;tap&lt;/code&gt;&lt;/strong&gt; ejecuta efectos secundarios sobre las emisiones, pero no modifica el valor que atraviesa el pipeline. Es una herramienta frecuente para depuración, métricas, logging o integración con observabilidad, siempre que no se use para alterar estado crítico de forma opaca.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-tap_hu_ca400b88414de95b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numbers$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;tap-antes&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;tap-despues&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;se terminó todo&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tap&lt;/code&gt; acepta un callback para &lt;code&gt;next&lt;/code&gt; o un objeto con handlers como &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;. En ambos casos, el valor que continúa hacia el siguiente operador permanece intacto.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-tap_hu_1fd193b2a444489d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Evita usar &lt;code&gt;tap&lt;/code&gt; como sustituto de &lt;code&gt;map&lt;/code&gt; o &lt;code&gt;filter&lt;/code&gt;. Si un paso cambia el valor del stream, debe expresarse con un operador de transformación explícito.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="reduce-acumular-y-emitir-al-completar"&gt;&lt;code&gt;reduce&lt;/code&gt;: acumular y emitir al completar&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt; aplica una función acumuladora sobre las emisiones y entrega un único resultado cuando el &lt;code&gt;Observable&lt;/code&gt; completa. Su comportamiento es apropiado para streams finitos, como arreglos, rangos o secuencias delimitadas con operadores como &lt;code&gt;take&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-reduce_hu_c634ff5213a00ec4.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;totalReducer&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;500&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;6&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;totalReducer&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El segundo argumento de &lt;code&gt;reduce&lt;/code&gt; define el valor inicial del acumulador. En el ejemplo, el acumulador inicia en &lt;code&gt;5&lt;/code&gt;, procesa seis emisiones del &lt;code&gt;interval&lt;/code&gt; y emite el total solo cuando &lt;code&gt;take(6)&lt;/code&gt; completa el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-reduce_hu_a2831c73d34ffa4b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;reduce&lt;/code&gt; necesita que el &lt;code&gt;Observable&lt;/code&gt; complete para emitir el resultado. En streams infinitos o de larga vida, como eventos del DOM sin delimitador, no recibirás salida si no aplicas un operador que cierre la secuencia.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="scan-acumular-y-emitir-cada-estado-intermedio"&gt;&lt;code&gt;scan&lt;/code&gt;: acumular y emitir cada estado intermedio&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;scan&lt;/code&gt;&lt;/strong&gt; también aplica una función acumuladora, pero emite cada estado intermedio del acumulador. Esta diferencia lo convierte en una pieza clave para modelar estado reactivo: contadores, historial de acciones, progreso incremental o snapshots derivados de eventos.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-scan_hu_104ac87779ead247.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Comparar &lt;code&gt;reduce&lt;/code&gt; y &lt;code&gt;scan&lt;/code&gt; sobre la misma secuencia deja clara la diferencia operativa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;totalAccumulator&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;totalAccumulator&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;reduce&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;totalAccumulator&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;scan&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;reduce&lt;/code&gt; emite solo el total final. &lt;code&gt;scan&lt;/code&gt; emite &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;6&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt; y &lt;code&gt;15&lt;/code&gt;, porque cada emisión representa el nuevo estado acumulado.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-reduce-scan_hu_9b17532d32728e9f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En arquitecturas reactivas, &lt;code&gt;scan&lt;/code&gt; suele ser más útil que &lt;code&gt;reduce&lt;/code&gt; cuando el consumidor necesita reaccionar a cada transición de estado, no solo al resultado final.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los operadores básicos de RxJS permiten convertir streams genéricos en flujos especializados y mantenibles. &lt;code&gt;map&lt;/code&gt; transforma, &lt;code&gt;filter&lt;/code&gt; controla qué continúa, &lt;code&gt;tap&lt;/code&gt; observa sin modificar, &lt;code&gt;reduce&lt;/code&gt; acumula hasta completar y &lt;code&gt;scan&lt;/code&gt; expone cada estado acumulado.&lt;/p&gt;
&lt;p&gt;Dominar &lt;code&gt;pipe&lt;/code&gt; y estos operadores establece una base sólida para operadores más avanzados. En el siguiente artículo de la serie abordaremos operadores de tiempo, donde la latencia, la frecuencia de emisión y la coordinación temporal pasan a ser parte central del diseño reactivo.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Funciones para crear Observables</title><link>https://blog.dacadev.com/typescript/rxjs/funciones-crear-observables/</link><pubDate>Sat, 30 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/funciones-crear-observables/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a crear observables RxJS con of, from, fromEvent, range, interval, timer y asyncScheduler en flujos síncronos y asíncronos.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#crear-observables-rxjs-con-funciones-de-creación"&gt;Crear observables RxJS con funciones de creación&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#of-emitir-cada-argumento-como-un-valor-independiente"&gt;&lt;code&gt;of&lt;/code&gt;: emitir cada argumento como un valor independiente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#from-convertir-iterables-arreglos-y-promesas-en-observables"&gt;&lt;code&gt;from&lt;/code&gt;: convertir iterables, arreglos y promesas en Observables&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#fromevent-crear-observables-desde-eventos-del-dom"&gt;&lt;code&gt;fromEvent&lt;/code&gt;: crear Observables desde eventos del DOM&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#identificar-el-tipo-del-evento-sin-usar-any"&gt;Identificar el tipo del evento sin usar &lt;code&gt;any&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#range-generar-secuencias-numéricas"&gt;&lt;code&gt;range&lt;/code&gt;: generar secuencias numéricas&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#rangecount-contar-desde-cero"&gt;&lt;code&gt;range(count)&lt;/code&gt;: contar desde cero&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#rangestart-count-definir-inicio-y-cantidad"&gt;&lt;code&gt;range(start, count)&lt;/code&gt;: definir inicio y cantidad&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#rangestart-count-asyncscheduler-diferir-la-ejecución"&gt;&lt;code&gt;range(start, count, asyncScheduler)&lt;/code&gt;: diferir la ejecución&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#interval-emitir-valores-periódicamente"&gt;&lt;code&gt;interval&lt;/code&gt;: emitir valores periódicamente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#timer-emitir-después-de-un-tiempo-o-iniciar-un-intervalo-diferido"&gt;&lt;code&gt;timer&lt;/code&gt;: emitir después de un tiempo o iniciar un intervalo diferido&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#configuraciones-especiales-de-timer"&gt;Configuraciones especiales de &lt;code&gt;timer&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#asyncscheduler-programar-trabajo-asíncrono"&gt;&lt;code&gt;asyncScheduler&lt;/code&gt;: programar trabajo asíncrono&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#reprogramar-una-tarea-y-cancelar-la-suscripción"&gt;Reprogramar una tarea y cancelar la suscripción&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando modelamos interacciones de usuario, temporizadores, colecciones o tareas diferidas, la decisión inicial suele ser cómo &lt;strong&gt;crear observables RxJS&lt;/strong&gt; sin introducir acoplamiento innecesario ni perder claridad sobre la sincronía del flujo. En &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;, las funciones de creación encapsulan patrones comunes para construir &lt;strong&gt;Observables&lt;/strong&gt; a partir de valores, iterables, eventos del DOM y relojes internos.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar &lt;a href="https://blog.dacadev.com/typescript/rxjs-observables/"



 


&gt;Observables&lt;/a&gt; y aquí abordaremos &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;fromEvent&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;timer&lt;/code&gt; y &lt;code&gt;asyncScheduler&lt;/code&gt;. El siguiente paso será estudiar &lt;a href="https://blog.dacadev.com/typescript/operadores-basicos-rxjs/"



 


&gt;Operadores básicos&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="crear-observables-rxjs-con-funciones-de-creación"&gt;Crear observables RxJS con funciones de creación&lt;/h2&gt;
&lt;p&gt;Las funciones de creación producen un &lt;code&gt;Observable&lt;/code&gt; sin escribir manualmente el constructor &lt;code&gt;new Observable(...)&lt;/code&gt;. Esto reduce código repetitivo y comunica la intención del stream: emitir valores estáticos, recorrer una colección, escuchar eventos o programar emisiones en el tiempo.&lt;/p&gt;
&lt;p&gt;La diferencia más importante está en la &lt;strong&gt;naturaleza síncrona o asíncrona&lt;/strong&gt; del observable resultante. &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt; y &lt;code&gt;range&lt;/code&gt; pueden emitir inmediatamente durante la suscripción. &lt;code&gt;fromEvent&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt; y &lt;code&gt;timer&lt;/code&gt;, en cambio, dependen de eventos externos o del paso del tiempo.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un observable puede ser finito o infinito. &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt; y &lt;code&gt;timer(2000)&lt;/code&gt; completan; &lt;code&gt;fromEvent&lt;/code&gt; e &lt;code&gt;interval&lt;/code&gt; no completan por sí mismos y requieren cancelar la suscripción o aplicar operadores como &lt;code&gt;take&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="of-emitir-cada-argumento-como-un-valor-independiente"&gt;&lt;code&gt;of&lt;/code&gt;: emitir cada argumento como un valor independiente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;of&lt;/code&gt; crea un observable síncrono a partir de los argumentos que recibe. Cada argumento se convierte en una emisión individual y, al terminar la lista, el stream envía &lt;code&gt;complete&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-of_hu_8d63db9b45300fec.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Esta característica es útil para valores estáticos, pruebas unitarias, mocks de servicios o flujos donde necesitas transformar una secuencia pequeña sin depender de una fuente externa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;string&amp;#39;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;, () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {}, &lt;span style="color:#d19a66"&gt;1.14&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio del obs$&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado!&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin del obs$&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Como &lt;code&gt;of&lt;/code&gt; es síncrono, todas las emisiones ocurren antes de ejecutar &lt;code&gt;console.log('Fin del obs$')&lt;/code&gt;. Esta propiedad es relevante cuando mezclas streams síncronos con lógica de UI o con efectos secundarios que dependen del orden de ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si pasas un arreglo a &lt;code&gt;of&lt;/code&gt;, el arreglo completo se emite como un único valor. Si necesitas emitir cada elemento del arreglo, usa &lt;code&gt;from&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="from-convertir-iterables-arreglos-y-promesas-en-observables"&gt;&lt;code&gt;from&lt;/code&gt;: convertir iterables, arreglos y promesas en Observables&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;from&lt;/code&gt; crea un observable a partir de estructuras que ya representan una secuencia o un valor diferido: arreglos, iterables, strings, &lt;code&gt;Promise&lt;/code&gt;, entre otros. Con un arreglo, emite cada elemento de manera independiente y luego completa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Batman&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Robin&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Joker&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;from&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-from_hu_631d68b1a4f8ad3c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La diferencia conceptual entre &lt;code&gt;of(personajes)&lt;/code&gt; y &lt;code&gt;from(personajes)&lt;/code&gt; es crítica. El primero emite un solo arreglo; el segundo emite tres objetos. Esa elección define el contrato del stream para los operadores posteriores.&lt;/p&gt;
&lt;h2 id="fromevent-crear-observables-desde-eventos-del-dom"&gt;&lt;code&gt;fromEvent&lt;/code&gt;: crear Observables desde eventos del DOM&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fromEvent&lt;/code&gt; convierte una fuente de eventos en un observable. Recibe el &lt;strong&gt;target&lt;/strong&gt; que expone eventos —por ejemplo &lt;code&gt;document&lt;/code&gt;, &lt;code&gt;window&lt;/code&gt; o un elemento HTML— y el nombre del evento.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-fromevent_hu_57a116438ce091e5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;clicks$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyups$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;clicks$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;click:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;keyups$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;event&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;key:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-fromevent_hu_68f1a422678c891d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este observable es infinito por defecto. El navegador seguirá emitiendo eventos mientras exista la suscripción, por lo que en componentes con ciclo de vida —por ejemplo Angular, React o Web Components— debes liberar recursos cuando el componente se desmonta.&lt;/p&gt;
&lt;h3 id="identificar-el-tipo-del-evento-sin-usar-any"&gt;Identificar el tipo del evento sin usar &lt;code&gt;any&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;En TypeScript conviene evitar &lt;code&gt;fromEvent&amp;lt;any&amp;gt;&lt;/code&gt;, porque rompe el contrato de tipos justo en la frontera del sistema. Una forma práctica de identificar el tipo consiste en inspeccionar temporalmente el evento y reemplazar &lt;code&gt;any&lt;/code&gt; por la interfaz específica.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;any&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/editor-event-type-inspection_hu_dce3b9c0b7946a91.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Al revisar el objeto emitido en consola o desde el editor, puedes identificar si corresponde a &lt;code&gt;PointerEvent&lt;/code&gt;, &lt;code&gt;KeyboardEvent&lt;/code&gt;, &lt;code&gt;MouseEvent&lt;/code&gt;, &lt;code&gt;InputEvent&lt;/code&gt; u otro tipo del DOM. Después reemplazas &lt;code&gt;any&lt;/code&gt; por el tipo correcto.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/editor-event-type-applied_hu_90ad704b8eae2a21.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;fromEvent&lt;/code&gt; no completa automáticamente. En flujos de UI, combina la suscripción con &lt;code&gt;takeUntil&lt;/code&gt;, &lt;code&gt;AbortController&lt;/code&gt;, el ciclo de vida del framework o una suscripción compuesta para evitar fugas de memoria.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="range-generar-secuencias-numéricas"&gt;&lt;code&gt;range&lt;/code&gt;: generar secuencias numéricas&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;range&lt;/code&gt; crea una secuencia numérica finita. Por defecto emite de forma síncrona, lo que permite usarlo para generar índices, alimentar pruebas o construir flujos deterministas.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-range_hu_6c23fd238ca55c84.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="rangecount-contar-desde-cero"&gt;&lt;code&gt;range(count)&lt;/code&gt;: contar desde cero&lt;/h3&gt;
&lt;p&gt;Cuando recibe un solo argumento, &lt;code&gt;range&lt;/code&gt; interpreta ese valor como la cantidad de emisiones. El conteo inicia en &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;src$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;src$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-range-count_hu_c37fa0c5e18bfd8d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El resultado emite &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt; y &lt;code&gt;4&lt;/code&gt;. No emite &lt;code&gt;5&lt;/code&gt;, porque el parámetro define la cantidad de valores, no el límite superior inclusivo.&lt;/p&gt;
&lt;h3 id="rangestart-count-definir-inicio-y-cantidad"&gt;&lt;code&gt;range(start, count)&lt;/code&gt;: definir inicio y cantidad&lt;/h3&gt;
&lt;p&gt;Con dos argumentos, el primero define el valor inicial y el segundo la cantidad de emisiones.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;src$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;src$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-range-start-count_hu_ae16b1835b3b46a9.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este stream emite &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;4&lt;/code&gt;, &lt;code&gt;5&lt;/code&gt; y &lt;code&gt;6&lt;/code&gt;. El contrato sigue siendo finito y síncrono.&lt;/p&gt;
&lt;h3 id="rangestart-count-asyncscheduler-diferir-la-ejecución"&gt;&lt;code&gt;range(start, count, asyncScheduler)&lt;/code&gt;: diferir la ejecución&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;asyncScheduler&lt;/code&gt; permite programar las emisiones de forma asíncrona. El cambio se observa en el orden de los &lt;code&gt;console.log&lt;/code&gt;: primero se ejecuta el código síncrono restante y luego comienzan las emisiones.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;range&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;src$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;src$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-range-asyncscheduler_hu_c450707bfca0f732.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncScheduler&lt;/code&gt; no convierte el trabajo en paralelismo real. Programa tareas asíncronas sobre la cola de ejecución, similar a diferir trabajo con temporizadores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="interval-emitir-valores-periódicamente"&gt;&lt;code&gt;interval&lt;/code&gt;: emitir valores periódicamente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;interval&lt;/code&gt; crea un observable asíncrono e infinito. Recibe un periodo en milisegundos y emite un contador incremental en cada tick.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-interval_hu_3f367558cb1b4263.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// En una aplicación real, cancela la suscripción según el ciclo de vida.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// subscription.unsubscribe();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-interval_hu_1b82e1dcf23f03fe.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;interval&lt;/code&gt; no emite &lt;code&gt;complete&lt;/code&gt;. Si necesitas un número limitado de emisiones, puedes combinarlo con operadores como &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt; o &lt;code&gt;timeout&lt;/code&gt;, que analizaremos en artículos posteriores de la serie.&lt;/p&gt;
&lt;h2 id="timer-emitir-después-de-un-tiempo-o-iniciar-un-intervalo-diferido"&gt;&lt;code&gt;timer&lt;/code&gt;: emitir después de un tiempo o iniciar un intervalo diferido&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;timer&lt;/code&gt; también es asíncrono, pero su configuración inicial es distinta. Con un único parámetro numérico, espera esa cantidad de milisegundos, emite &lt;code&gt;0&lt;/code&gt; y completa.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-timer_hu_c5ef5784484f6fc5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-timer_hu_bab5418d019c3a86.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="configuraciones-especiales-de-timer"&gt;Configuraciones especiales de &lt;code&gt;timer&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;timer&lt;/code&gt; acepta configuraciones que cubren varios casos operativos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timer(0)&lt;/code&gt; agenda la emisión tan pronto como la cola de tareas lo permita, después del trabajo síncrono actual.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timer(2000, 1000)&lt;/code&gt; espera dos segundos y luego se comporta como un intervalo que emite cada segundo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timer(fecha)&lt;/code&gt; permite agendar la primera emisión para un instante específico usando un objeto &lt;code&gt;Date&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;timer(2000, 1000)&lt;/code&gt; deja de ser finito. Después de la primera emisión, continúa como un intervalo y debe cancelarse cuando ya no sea necesario.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="asyncscheduler-programar-trabajo-asíncrono"&gt;&lt;code&gt;asyncScheduler&lt;/code&gt;: programar trabajo asíncrono&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncScheduler&lt;/code&gt; permite programar tareas usando la infraestructura de schedulers de RxJS. Puede reemplazar casos simples de &lt;code&gt;setTimeout&lt;/code&gt; y habilita patrones donde una tarea se reprograma a sí misma.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hola mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-asyncscheduler-immediate_hu_d8901f49376da41c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;También puedes definir un retraso explícito en milisegundos y pasar un único estado a la función programada.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`hola mundo, &lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-asyncscheduler-argument_hu_54af5b19a60430e.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Si necesitas pasar múltiples valores, usa un objeto como estado y desestructúralo en la función. Esto mantiene una firma estable y evita depender de parámetros posicionales adicionales.&lt;/p&gt;
&lt;h3 id="reprogramar-una-tarea-y-cancelar-la-suscripción"&gt;Reprogramar una tarea y cancelar la suscripción&lt;/h3&gt;
&lt;p&gt;Una acción programada puede invocar &lt;code&gt;this.schedule(...)&lt;/code&gt; para encadenar la siguiente ejecución. La suscripción resultante permite detener el ciclo.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;SchedulerAction&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;SchedulerAction&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;state&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;state&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;state&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;state&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Unsubscribe&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;6000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-asyncscheduler-recursive_hu_201ae045c15be6d4.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa schedulers cuando necesites controlar explícitamente cuándo ocurre la ejecución. Para transformación de streams, normalmente conviene preferir operadores de RxJS antes que programar tareas manualmente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Las funciones de creación definen el contrato inicial del stream. &lt;code&gt;of&lt;/code&gt; emite argumentos, &lt;code&gt;from&lt;/code&gt; expande estructuras iterables o promesas, &lt;code&gt;fromEvent&lt;/code&gt; conecta eventos del DOM, &lt;code&gt;range&lt;/code&gt; genera secuencias numéricas, &lt;code&gt;interval&lt;/code&gt; modela ticks periódicos y &lt;code&gt;timer&lt;/code&gt; cubre emisiones diferidas o intervalos con retardo inicial.&lt;/p&gt;
&lt;p&gt;Dominar estas diferencias evita errores sutiles de sincronía, fugas de suscripción y contratos ambiguos entre productores y consumidores. Con esta base, el siguiente paso natural es aplicar operadores para transformar, filtrar y combinar emisiones dentro de una arquitectura reactiva mantenible.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Observables, Subscriptions y Subjects</title><link>https://blog.dacadev.com/typescript/rxjs/rxjs-observables/</link><pubDate>Thu, 28 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/rxjs-observables/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende observables rxjs con new Observable, Observer, subscribe unsubscribe, teardown y Subject para flujos multicast en TypeScript.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/observables/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#crear-observables-rxjs-con-new-observable"&gt;Crear observables rxjs con &lt;code&gt;new Observable&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-interfaz-observer-next-error-y-complete"&gt;La interfaz &lt;code&gt;Observer&lt;/code&gt;: &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#subscription-y-unsubscribe-controlar-la-vida-útil-del-stream"&gt;&lt;code&gt;Subscription&lt;/code&gt; y &lt;code&gt;unsubscribe&lt;/code&gt;: controlar la vida útil del stream&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#finalizar-desde-el-observable-con-complete"&gt;Finalizar desde el observable con &lt;code&gt;complete()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#encadenar-suscripciones-con-add"&gt;Encadenar suscripciones con &lt;code&gt;.add()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#subject-rxjs-multicast-y-observable-caliente"&gt;&lt;code&gt;Subject RxJS&lt;/code&gt;: multicast y observable caliente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#emitir-y-completar-desde-un-subject"&gt;Emitir y completar desde un &lt;code&gt;Subject&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando un flujo asíncrono combina eventos de usuario, timers, llamadas HTTP y actualizaciones de estado, el problema no es solo recibir datos: es modelar correctamente la vida útil de cada stream. &lt;strong&gt;Observables RxJS&lt;/strong&gt; permite representar esos flujos como secuencias cancelables, componibles y explícitas, con una semántica clara para emisión, error, finalización y limpieza de recursos.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de &lt;a href="https://blog.dacadev.com/typescript/introduccion-extensiones-reactivas/"



 


&gt;Introducción a las extensiones reactivas&lt;/a&gt; y aquí analizaremos &lt;code&gt;Observable&lt;/code&gt;, &lt;code&gt;Observer&lt;/code&gt;, &lt;code&gt;Subscription&lt;/code&gt;, &lt;code&gt;unsubscribe&lt;/code&gt;, teardown callbacks y &lt;code&gt;Subject&lt;/code&gt;. El siguiente paso será &lt;a href="https://blog.dacadev.com/typescript/funciones-crear-observables/"



 


&gt;Funciones para crear Observables&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="crear-observables-rxjs-con-new-observable"&gt;Crear observables rxjs con &lt;code&gt;new Observable&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;En &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;, un &lt;strong&gt;Observable&lt;/strong&gt; representa una fuente de valores que puede emitir cero, uno o muchos elementos a lo largo del tiempo. La forma más directa de construir uno es instanciar &lt;code&gt;Observable&lt;/code&gt; y entregar una función de suscripción. Esa función recibe un &lt;code&gt;subscriber&lt;/code&gt;, que actúa como canal para emitir valores con &lt;code&gt;next&lt;/code&gt;, reportar errores con &lt;code&gt;error&lt;/code&gt; o finalizar con &lt;code&gt;complete&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// Después de complete(), estas emisiones ya no llegan al consumidor.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La convención del sufijo &lt;code&gt;$&lt;/code&gt; en &lt;code&gt;obs$&lt;/code&gt; no es obligatoria, pero ayuda a comunicar que una variable representa un stream. También es importante declarar el tipo del observable, por ejemplo &lt;code&gt;Observable&amp;lt;string&amp;gt;&lt;/code&gt;, porque TypeScript podrá validar el contrato entre la fuente y sus consumidores.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;complete()&lt;/code&gt; no destruye el objeto observable; cierra la ejecución de esa suscripción específica. A partir de ese punto, el consumidor ya no recibe nuevas emisiones de esa instancia de ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Modela el tipo del stream desde el inicio. Un &lt;code&gt;Observable&amp;lt;User&amp;gt;&lt;/code&gt; comunica mucho más que un &lt;code&gt;Observable&amp;lt;unknown&amp;gt;&lt;/code&gt; y reduce errores en operadores, observers y callbacks de suscripción.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="la-interfaz-observer-next-error-y-complete"&gt;La interfaz &lt;code&gt;Observer&lt;/code&gt;: &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Para consumir un observable usamos &lt;code&gt;subscribe&lt;/code&gt;. En versiones modernas de RxJS es preferible pasar un objeto compatible con la interfaz &lt;strong&gt;Observer&lt;/strong&gt;, en lugar de usar la sobrecarga antigua de tres callbacks separados.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Observer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Observer&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;siguiente&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;completado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La interfaz divide explícitamente los tres canales del stream:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;next&lt;/code&gt;: se ejecuta cada vez que el observable emite un valor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;error&lt;/code&gt;: se ejecuta cuando la fuente reporta un fallo terminal.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete&lt;/code&gt;: se ejecuta cuando la fuente finaliza correctamente.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt; son señales terminales. Después de cualquiera de ellas, la suscripción queda cerrada y no debe esperarse más trabajo desde esa ejecución.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Forma antigua: evita esta sobrecarga en código nuevo.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Forma recomendada.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La documentación oficial de &lt;a href="https://reactivex.io"




 target="_blank"
 


&gt;ReactiveX&lt;/a&gt; describe este contrato como una secuencia de notificaciones donde el observable invoca al observer. RxJS conserva esa idea y la adapta al ecosistema JavaScript con cancelación explícita mediante suscripciones.&lt;/p&gt;
&lt;h2 id="subscription-y-unsubscribe-controlar-la-vida-útil-del-stream"&gt;&lt;code&gt;Subscription&lt;/code&gt; y &lt;code&gt;unsubscribe&lt;/code&gt;: controlar la vida útil del stream&lt;/h2&gt;
&lt;p&gt;Cada llamada a &lt;code&gt;subscribe&lt;/code&gt; crea una &lt;strong&gt;Subscription&lt;/strong&gt;. Esa suscripción representa la ejecución activa entre un observable y un consumidor. Si el observable administra recursos externos, como un &lt;code&gt;setInterval&lt;/code&gt;, un WebSocket o un listener del DOM, la suscripción debe liberar esos recursos cuando el consumidor ya no los necesita.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Intervalo destruido&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs1:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs2:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs3:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado Timeout&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;3000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-intervalos_hu_44a3eabde95f1ade.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En este ejemplo, cada suscripción recibe su propio contador porque el observable es &lt;strong&gt;cold&lt;/strong&gt;: la producción de datos ocurre dentro de la función de suscripción. Tres suscripciones implican tres ejecuciones independientes del &lt;code&gt;setInterval&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La función retornada desde el constructor del observable es el &lt;strong&gt;teardown callback&lt;/strong&gt;. RxJS la ejecuta cuando llamamos &lt;code&gt;unsubscribe()&lt;/code&gt; o cuando la suscripción se cierra por una señal terminal. Es el lugar correcto para liberar timers, conexiones, listeners o cualquier recurso asociado a esa ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No tratar &lt;code&gt;unsubscribe()&lt;/code&gt; como un detalle opcional puede producir fugas de memoria y procesos activos innecesarios. En streams infinitos, como &lt;code&gt;interval&lt;/code&gt;, eventos del DOM o sockets, la limpieza explícita es parte del diseño.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="finalizar-desde-el-observable-con-complete"&gt;Finalizar desde el observable con &lt;code&gt;complete()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;También es posible cerrar la suscripción desde la propia fuente. Para ello, el observable invoca &lt;code&gt;subscriber.complete()&lt;/code&gt;. Cuando esto ocurre, RxJS ejecuta el callback &lt;code&gt;complete&lt;/code&gt; del observer y posteriormente ejecuta el teardown registrado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Observer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Observer&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;siguiente&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;completado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;obs:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;2500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Intervalo destruido&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado Timeout&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;6000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-complete_hu_5598a64f18fe7fdf.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Aunque el &lt;code&gt;setTimeout&lt;/code&gt; final intenta cancelar las suscripciones a los seis segundos, cada una ya fue completada por el observable a los 2.5 segundos. La llamada posterior a &lt;code&gt;unsubscribe()&lt;/code&gt; no vuelve a emitir &lt;code&gt;complete&lt;/code&gt;; simplemente opera sobre una suscripción cerrada.&lt;/p&gt;
&lt;p&gt;Esta diferencia es relevante en diseño de APIs. &lt;code&gt;complete()&lt;/code&gt; comunica que la fuente terminó correctamente; &lt;code&gt;unsubscribe()&lt;/code&gt; comunica que el consumidor ya no quiere recibir valores. Ambas rutas cierran la suscripción, pero expresan intenciones distintas.&lt;/p&gt;
&lt;h2 id="encadenar-suscripciones-con-add"&gt;Encadenar suscripciones con &lt;code&gt;.add()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Cuando varias suscripciones comparten el mismo ciclo de vida, RxJS permite agruparlas con &lt;code&gt;.add()&lt;/code&gt;. Esto evita repetir llamadas a &lt;code&gt;unsubscribe()&lt;/code&gt; y centraliza la limpieza en una suscripción raíz.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado Timeout&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;6000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al cancelar &lt;code&gt;subs1&lt;/code&gt;, RxJS cancela también las suscripciones agregadas. Este patrón resulta útil cuando un componente, servicio o caso de uso crea múltiples streams relacionados y necesita destruirlos como una unidad.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Agrupa suscripciones solo cuando comparten el mismo ownership. Si dos streams tienen ciclos de vida diferentes, unirlos artificialmente puede cancelar trabajo legítimo antes de tiempo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="subject-rxjs-multicast-y-observable-caliente"&gt;&lt;code&gt;Subject RxJS&lt;/code&gt;: multicast y observable caliente&lt;/h2&gt;
&lt;p&gt;Un &lt;strong&gt;Subject&lt;/strong&gt; combina dos roles: es un observable y también es un observer. Puede recibir valores mediante &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; o &lt;code&gt;complete&lt;/code&gt;, y al mismo tiempo permite que múltiples consumidores se suscriban a él.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;Math&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;random&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;3000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;num&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs1:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;num&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs2:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-subject_hu_4facf6ec81c8737f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La diferencia clave es que &lt;code&gt;Subject&lt;/code&gt; habilita &lt;strong&gt;multicast&lt;/strong&gt;: una sola ejecución de la fuente puede distribuir la misma emisión a varios observers. En lugar de crear un &lt;code&gt;setInterval&lt;/code&gt; por cada consumidor, el &lt;code&gt;Subject&lt;/code&gt; actúa como punto de difusión.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[Observable fuente] --&gt; B[Subject]
 B --&gt; C[Observer 1]
 B --&gt; D[Observer 2]
 B --&gt; E[Observer 3]
&lt;/pre&gt;

&lt;p&gt;En términos de hot y cold observables, un observable es &lt;strong&gt;cold&lt;/strong&gt; cuando la producción de datos ocurre dentro de la suscripción y cada consumidor obtiene su propia ejecución. Un observable es &lt;strong&gt;hot&lt;/strong&gt; cuando la producción de datos existe fuera de una suscripción individual y puede compartirse entre varios consumidores.&lt;/p&gt;
&lt;p&gt;El &lt;code&gt;Subject&lt;/code&gt; puede convertir un flujo cold en un flujo hot desde la perspectiva de los subscribers conectados al subject. La fuente se ejecuta una vez y el &lt;code&gt;Subject&lt;/code&gt; distribuye los valores a múltiples listeners.&lt;/p&gt;
&lt;h2 id="emitir-y-completar-desde-un-subject"&gt;Emitir y completar desde un &lt;code&gt;Subject&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Como &lt;code&gt;Subject&lt;/code&gt; también es un observer, puede emitir valores propios. Esto permite introducir valores manualmente en el stream, además de reenviar los valores provenientes de una fuente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Observer&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Observer&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;siguiente&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;completado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;Math&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;random&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;SetInterval terminado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;baseInterval&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;baseInterval&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;3500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-hot_hu_d0473069b092df1a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El detalle operativo es importante: llamar &lt;code&gt;subject$.complete()&lt;/code&gt; cierra el subject y notifica a sus suscriptores, pero no necesariamente cancela la suscripción original que alimentaba al subject. Por eso el ejemplo ejecuta &lt;code&gt;baseInterval.unsubscribe()&lt;/code&gt; de forma explícita.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un &lt;code&gt;Subject&lt;/code&gt; concentra poder y acoplamiento. Úsalo cuando necesitas multicast o una frontera explícita entre productor y consumidores; evita convertirlo en un bus global mutable sin ownership claro.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los &lt;strong&gt;observables rxjs&lt;/strong&gt; ofrecen un contrato robusto para representar streams asíncronos en TypeScript. &lt;code&gt;Observer&lt;/code&gt; define cómo reaccionar ante &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;; &lt;code&gt;Subscription&lt;/code&gt; controla la vida útil de la ejecución; &lt;code&gt;unsubscribe()&lt;/code&gt; dispara la limpieza mediante el teardown callback; y &lt;code&gt;.add()&lt;/code&gt; permite componer ciclos de vida relacionados.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Subject&lt;/code&gt; amplía el modelo al habilitar multicast y convertir flujos cold en flujos hot bajo ciertas condiciones. Esta capacidad es útil, pero exige ownership explícito: completar el subject y cancelar la fuente no siempre son la misma operación.&lt;/p&gt;
&lt;p&gt;En el siguiente artículo abordaremos las &lt;a href="https://blog.dacadev.com/typescript/funciones-crear-observables/"



 


&gt;funciones para crear Observables&lt;/a&gt;, una forma más declarativa y menos manual de construir streams con RxJS.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Introducción a las extensiones reactivas</title><link>https://blog.dacadev.com/typescript/rxjs/introduccion-extensiones-reactivas/</link><pubDate>Tue, 26 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/introduccion-extensiones-reactivas/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende programación reactiva con RxJs, ReactiveX, Observables, Subscribers, operadores, diagramas de canicas y setup inicial.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/intro/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#por-qué-usar-extensiones-reactivas-en-aplicaciones-web"&gt;Por qué usar extensiones reactivas en aplicaciones web&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuándo-usar-programación-reactiva-con-rxjs"&gt;Cuándo usar programación reactiva con RxJs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#elementos-de-las-extensiones-reactivas"&gt;Elementos de las extensiones reactivas&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#observables-la-fuente-de-información"&gt;Observables: la fuente de información&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#subscribers-consumidores-del-flujo"&gt;Subscribers: consumidores del flujo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#operators-transformación-filtrado-y-composición"&gt;Operators: transformación, filtrado y composición&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#beneficios-de-rxjs-y-las-extensiones-reactivas"&gt;Beneficios de RxJs y las extensiones reactivas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#qué-es-reactivex"&gt;Qué es ReactiveX&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#patrón-observer-notificación-uno-a-muchos"&gt;Patrón Observer: notificación uno a muchos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#patrón-iterator-operaciones-secuenciales"&gt;Patrón Iterator: operaciones secuenciales&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#programación-funcional-composición-sin-mutación"&gt;Programación funcional: composición sin mutación&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#diagrama-de-canicas-en-rxjs"&gt;Diagrama de canicas en RxJs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#configuración-del-proyecto-para-la-serie-rxjs"&gt;Configuración del proyecto para la serie RxJs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En aplicaciones web modernas, la &lt;strong&gt;programación reactiva&lt;/strong&gt; aparece cuando el sistema debe responder a múltiples fuentes de eventos sin bloquear la interfaz: entradas del usuario, respuestas HTTP, mensajes por WebSocket, timers, estado compartido y cambios que llegan en momentos distintos. Administrar esos flujos solo con callbacks o promesas aisladas suele aumentar el acoplamiento y dificulta expresar transformaciones, cancelaciones y composición de eventos. &lt;strong&gt;RxJs&lt;/strong&gt; aborda este problema con &lt;strong&gt;extensiones reactivas&lt;/strong&gt; basadas en flujos de datos observables.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo abre la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Analizaremos qué son las extensiones reactivas, qué papel cumple ReactiveX, cómo se relacionan Observables, Subscribers y Operators, cómo leer diagramas de canicas y cómo preparar el proyecto base. No hay artículo anterior; el siguiente artículo es &lt;a href="https://blog.dacadev.com/typescript/rxjs-observables/"



 


&gt;Observables&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="por-qué-usar-extensiones-reactivas-en-aplicaciones-web"&gt;Por qué usar extensiones reactivas en aplicaciones web&lt;/h2&gt;
&lt;p&gt;La expectativa actual de una interfaz es operar en tiempo real o casi real. Un formulario con autocompletado, un dashboard con métricas en vivo o una pantalla de trading no puede depender de recargas completas de página para reflejar cambios. La aplicación necesita reaccionar a eventos concurrentes y mantener la experiencia de usuario estable mientras ejecuta trabajo asíncrono.&lt;/p&gt;
&lt;p&gt;Las &lt;strong&gt;extensiones reactivas&lt;/strong&gt; permiten modelar esos eventos como flujos. En lugar de distribuir lógica en múltiples callbacks, representamos la fuente de datos como un &lt;code&gt;Observable&lt;/code&gt; y aplicamos operadores para transformar, filtrar, combinar o controlar la frecuencia de sus emisiones.&lt;/p&gt;
&lt;p&gt;Esta aproximación es útil cuando una interacción puede producir muchos valores a lo largo del tiempo. Una promesa representa un resultado único; un observable puede representar cero, uno, muchos o infinitos valores, además de errores y finalización.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;searchInput&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#search&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;searchTerm$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;searchInput&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;searchTerm$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;term&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Buscar:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;term&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El sufijo &lt;code&gt;$&lt;/code&gt; en &lt;code&gt;searchTerm$&lt;/code&gt; es una convención frecuente para indicar que la variable representa un flujo observable. No es obligatorio, pero mejora la legibilidad cuando conviven valores normales y streams.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa RxJs cuando necesites componer eventos en el tiempo: entradas de usuario, sockets, polling, estado reactivo, cancelaciones, reintentos y coordinación entre múltiples fuentes asíncronas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cuándo-usar-programación-reactiva-con-rxjs"&gt;Cuándo usar programación reactiva con RxJs&lt;/h2&gt;
&lt;p&gt;RxJs aporta más valor cuando el problema se expresa naturalmente como una secuencia de emisiones. No todos los casos asíncronos requieren un &lt;code&gt;Observable&lt;/code&gt;; una petición HTTP aislada puede resolverse con &lt;code&gt;Promise&lt;/code&gt; sin introducir más abstracción. El punto fuerte de RxJs aparece cuando necesitas componer varias señales y mantener control explícito sobre su ciclo de vida.&lt;/p&gt;
&lt;p&gt;Casos comunes de uso:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Eventos de interfaz de usuario&lt;/strong&gt;: clicks, movimientos del mouse, inputs, scroll o drag and drop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notificación de cambios en objetos o estado compartido&lt;/strong&gt;: propagación de cambios hacia múltiples consumidores.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comunicación por sockets&lt;/strong&gt;: mensajes que llegan indefinidamente y deben procesarse con filtros o transformaciones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flujos de información&lt;/strong&gt;: secuencias que pueden combinar datos de red, timers, cache y eventos locales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control de concurrencia&lt;/strong&gt;: cancelación de peticiones obsoletas, serialización de operaciones o limitación de frecuencia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consideremos un autocompletado. Cada tecla puede disparar una solicitud de red, pero no todas las solicitudes siguen siendo relevantes. RxJs permite aplicar &lt;code&gt;debounceTime&lt;/code&gt;, eliminar valores repetidos con &lt;code&gt;distinctUntilChanged&lt;/code&gt; y cancelar peticiones previas con &lt;code&gt;switchMap&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;query$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;searchInput&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fetch&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`/api/search?q=&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;encodeURIComponent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La implementación expresa la intención del flujo: capturar entrada, esperar estabilidad, evitar duplicados y ejecutar la consulta vigente. La lógica queda declarativa y evita coordinación manual con banderas de estado mutable.&lt;/p&gt;
&lt;h2 id="elementos-de-las-extensiones-reactivas"&gt;Elementos de las extensiones reactivas&lt;/h2&gt;
&lt;p&gt;RxJs organiza su modelo alrededor de tres piezas principales: &lt;strong&gt;Observables&lt;/strong&gt;, &lt;strong&gt;Subscribers&lt;/strong&gt; y &lt;strong&gt;Operators&lt;/strong&gt;. Entender la responsabilidad de cada una evita mezclar producción de datos, consumo y transformación en el mismo bloque de código.&lt;/p&gt;
&lt;h3 id="observables-la-fuente-de-información"&gt;Observables: la fuente de información&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;Observable&lt;/strong&gt; representa una fuente de valores a lo largo del tiempo. Puede emitir múltiples valores, un único valor o ninguno. También puede emitir un error o completar su ciclo de vida.&lt;/p&gt;
&lt;p&gt;Sus propiedades principales son:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Puede ser finito o infinito.&lt;/li&gt;
&lt;li&gt;Puede emitir de forma síncrona o asíncrona.&lt;/li&gt;
&lt;li&gt;Puede notificar valores, errores y finalización.&lt;/li&gt;
&lt;li&gt;Puede encapsular detalles internos como eventos DOM, sockets, timers o APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo, &lt;code&gt;counter$&lt;/code&gt; define la fuente de emisiones. La ejecución real ocurre cuando alguien se suscribe; antes de eso, solo existe la definición del flujo.&lt;/p&gt;
&lt;h3 id="subscribers-consumidores-del-flujo"&gt;Subscribers: consumidores del flujo&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;Subscriber&lt;/strong&gt; consume las emisiones de un observable. Puede reaccionar a valores (&lt;code&gt;next&lt;/code&gt;), errores (&lt;code&gt;error&lt;/code&gt;) y finalización (&lt;code&gt;complete&lt;/code&gt;). La suscripción también representa un recurso que debe liberarse cuando el flujo deja de ser necesario, especialmente en observables infinitos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Valor:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Flujo completado&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El consumidor no necesita conocer si los datos provienen de un arreglo, un WebSocket, un evento DOM o una API. Esa separación reduce el acoplamiento entre la fuente de datos y quienes procesan sus emisiones.&lt;/p&gt;
&lt;h3 id="operators-transformación-filtrado-y-composición"&gt;Operators: transformación, filtrado y composición&lt;/h3&gt;
&lt;p&gt;Los &lt;strong&gt;Operators&lt;/strong&gt; son funciones que permiten trabajar con observables sin mutar directamente la fuente original. Se encadenan mediante &lt;code&gt;pipe()&lt;/code&gt; y habilitan operaciones de transformación, filtrado, combinación y creación.&lt;/p&gt;
&lt;p&gt;Algunos operadores frecuentes son:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transformación: &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;scan&lt;/code&gt;, &lt;code&gt;groupBy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Filtrado: &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;distinctUntilChanged&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;, &lt;code&gt;debounceTime&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Combinación: &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt;, &lt;code&gt;zip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creación: &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;timer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;%&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí el flujo filtra impares, transforma cada emisión y acumula el resultado. La fuente original no se modifica; cada operador devuelve un nuevo observable derivado.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La composición con operadores es una de las razones principales para adoptar RxJs: permite expresar pipelines asíncronos complejos con una semántica consistente para valores, errores y finalización.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="beneficios-de-rxjs-y-las-extensiones-reactivas"&gt;Beneficios de RxJs y las extensiones reactivas&lt;/h2&gt;
&lt;p&gt;El beneficio más visible de RxJs es evitar estructuras difíciles de mantener como el callback hell. Sin embargo, su valor no se limita a reemplazar callbacks. RxJs ofrece un modelo uniforme para tratar trabajo síncrono y asíncrono como flujos componibles.&lt;/p&gt;
&lt;p&gt;Entre sus ventajas principales están:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reduce el anidamiento de callbacks y centraliza la lógica del flujo.&lt;/li&gt;
&lt;li&gt;Permite trabajar con tareas síncronas y asíncronas bajo la misma abstracción.&lt;/li&gt;
&lt;li&gt;Usa operadores para simplificar transformación, filtrado y composición.&lt;/li&gt;
&lt;li&gt;Facilita modificar streams sin alterar el consumidor final.&lt;/li&gt;
&lt;li&gt;Mejora la legibilidad cuando el problema depende de eventos en el tiempo.&lt;/li&gt;
&lt;li&gt;Permite anexar pasos al pipeline sin reescribir toda la implementación.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Esta capacidad de composición es especialmente relevante en aplicaciones grandes. Puedes aislar responsabilidades en operadores específicos y mantener flujos más predecibles, en lugar de dispersar estado mutable entre handlers independientes.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;RxJs no elimina la complejidad del dominio. La desplaza hacia un modelo explícito de streams. Si el problema no involucra secuencias, cancelación, coordinación o múltiples emisiones, una abstracción más simple puede ser suficiente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="qué-es-reactivex"&gt;Qué es ReactiveX&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://reactivex.io"




 target="_blank"
 


&gt;&lt;strong&gt;ReactiveX&lt;/strong&gt;&lt;/a&gt; es una API para programación asíncrona basada en observables. Su objetivo es proporcionar una forma consistente de componer secuencias de eventos y datos a través de operadores. RxJs es la implementación de ReactiveX para JavaScript y TypeScript, documentada oficialmente en &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;rxjs.dev&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ReactiveX se apoya en tres ideas fundamentales: el patrón Observer, el patrón Iterator y la programación funcional. La combinación de estas ideas explica por qué RxJs puede representar datos que llegan en el tiempo, recorrer secuencias y aplicar transformaciones sin mutar la fuente.&lt;/p&gt;
&lt;h3 id="patrón-observer-notificación-uno-a-muchos"&gt;Patrón Observer: notificación uno a muchos&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;patrón Observer&lt;/strong&gt; define una relación uno a muchos entre objetos. Cuando el sujeto cambia su estado, notifica a todos sus observadores. En RxJs, el observable cumple el rol de fuente y cada suscripción representa un consumidor interesado en sus emisiones.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 S[Observable / Subject] --&gt;|next value| A[Subscriber A]
 S --&gt;|next value| B[Subscriber B]
 S --&gt;|next value| C[Subscriber C]
 S --&gt;|error / complete| A
 S --&gt;|error / complete| B
 S --&gt;|error / complete| C
&lt;/pre&gt;

&lt;p&gt;Este patrón resulta natural para interfaces, sockets y estado compartido. La fuente emite cambios y los consumidores reaccionan sin conocer los detalles internos de producción.&lt;/p&gt;
&lt;h3 id="patrón-iterator-operaciones-secuenciales"&gt;Patrón Iterator: operaciones secuenciales&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;patrón Iterator&lt;/strong&gt; define una forma de acceder secuencialmente a los elementos de una colección. ReactiveX toma esa idea y la proyecta sobre el tiempo: en lugar de recorrer una colección ya disponible, procesa valores conforme se emiten.&lt;/p&gt;
&lt;p&gt;Un arreglo entrega valores inmediatamente. Un observable puede entregar valores ahora, más tarde o nunca completar. Esa diferencia temporal es la razón por la que los operadores de RxJs son tan útiles para coordinar flujos asíncronos.&lt;/p&gt;
&lt;h3 id="programación-funcional-composición-sin-mutación"&gt;Programación funcional: composición sin mutación&lt;/h3&gt;
&lt;p&gt;La &lt;strong&gt;programación funcional&lt;/strong&gt; aporta la idea de construir transformaciones con funciones específicas, predecibles y sin efectos secundarios innecesarios. Operadores como &lt;code&gt;map&lt;/code&gt; y &lt;code&gt;filter&lt;/code&gt; no mutan la fuente; generan nuevos observables derivados.&lt;/p&gt;
&lt;p&gt;Esta disciplina reduce el acoplamiento y facilita razonar sobre el flujo. Cada operador cumple una responsabilidad concreta y el pipeline completo documenta el recorrido de los datos.&lt;/p&gt;
&lt;h2 id="diagrama-de-canicas-en-rxjs"&gt;Diagrama de canicas en RxJs&lt;/h2&gt;
&lt;p&gt;Los &lt;strong&gt;diagramas de canicas&lt;/strong&gt; son una convención visual para explicar cómo se comportan los observables a lo largo del tiempo. Cada línea representa un stream, cada canica representa una emisión, las barras verticales indican finalización y los operadores muestran cómo se transforma el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/intro/marble-diagram_hu_4f81c4fa30911f02.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este tipo de diagrama es especialmente útil para entender operadores temporales como &lt;code&gt;debounceTime&lt;/code&gt;, &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt; o &lt;code&gt;concatMap&lt;/code&gt;. En lugar de describir cada emisión con texto, el diagrama permite comparar el flujo de entrada, el operador aplicado y el flujo resultante.&lt;/p&gt;
&lt;p&gt;Al leer un diagrama de canicas, considera estos puntos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;El tiempo avanza de izquierda a derecha.&lt;/li&gt;
&lt;li&gt;Cada símbolo o canica representa una emisión del observable.&lt;/li&gt;
&lt;li&gt;La barra vertical representa &lt;code&gt;complete&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Una &lt;code&gt;X&lt;/code&gt; suele representar &lt;code&gt;error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Los operadores transforman la relación entre entrada y salida.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Cuando estudies un operador nuevo, revisa primero su diagrama de canicas y después valida el comportamiento con código. Esa secuencia reduce ambigüedad en operadores temporales y de concurrencia.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="configuración-del-proyecto-para-la-serie-rxjs"&gt;Configuración del proyecto para la serie RxJs&lt;/h2&gt;
&lt;p&gt;Para seguir la serie usaremos como base el repositorio del curso de Klerith: &lt;a href="https://github.com/Klerith/curso-rxjs-inicio"




 target="_blank"
 


&gt;Klerith/curso-rxjs-inicio&lt;/a&gt;. Este proyecto proporciona una estructura inicial para practicar RxJs sin dedicar tiempo a configurar desde cero el entorno.&lt;/p&gt;
&lt;p&gt;Puedes clonar el repositorio y preparar las dependencias con los comandos habituales:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/Klerith/curso-rxjs-inicio.git
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;cd&lt;/span&gt; curso-rxjs-inicio
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si prefieres crear un proyecto propio, instala RxJs desde npm y configura TypeScript según tu stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install rxjs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El objetivo de esta serie no es cubrir la configuración de bundlers, sino entender el modelo mental de RxJs y sus operadores. Mantener un proyecto pequeño al inicio permite enfocarse en observables, suscripciones, composición y manejo del ciclo de vida.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;RxJs permite modelar eventos y datos asíncronos como flujos observables. Esta abstracción es útil cuando la aplicación necesita reaccionar a múltiples emisiones, coordinar fuentes, transformar datos y controlar el ciclo de vida de suscripciones.&lt;/p&gt;
&lt;p&gt;ReactiveX combina Observer, Iterator y programación funcional para construir una API coherente alrededor de streams. En el siguiente artículo profundizaremos en &lt;a href="https://blog.dacadev.com/typescript/rxjs-observables/"



 


&gt;Observables&lt;/a&gt;: cómo se crean, cuándo ejecutan, qué implica suscribirse y cómo gestionar su finalización correctamente.&lt;/p&gt;</content:encoded></item></channel></rss>