<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>RxJs Lessons Archives - Ronnie Schaniel</title>
	<atom:link href="https://ronnieschaniel.com/tag/rxjs-lessons/feed/" rel="self" type="application/rss+xml" />
	<link>https://ronnieschaniel.com/tag/rxjs-lessons/</link>
	<description>Blog</description>
	<lastBuildDate>Sun, 21 Dec 2025 10:27:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>RxJS Mastery &#8211; How to build streams</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-how-to-build-streams/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Mon, 11 Mar 2024 16:05:53 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2367</guid>

					<description><![CDATA[<p>Use RxJS without frustration. Build your streams successfully step-by-step.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-how-to-build-streams/">RxJS Mastery &#8211; How to build streams</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="392" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_mastery_how_to_build_streams-1024x392.png" alt="" class="wp-image-2369" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_mastery_how_to_build_streams-1024x392.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_mastery_how_to_build_streams-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_mastery_how_to_build_streams-768x294.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_mastery_how_to_build_streams-1536x588.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_mastery_how_to_build_streams.png 1660w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I have often seen people struggling when using RxJS. They are frustrated because they try too much at once, do not have proper tests, or have difficulties understanding error messages. How can you do RxJS development effectively and efficiently? I give my view on that in this article. Done right, RxJS development is easy because the library offers a lot of solutions for the usually difficult asynchronous programming.</p>



<h2 class="wp-block-heading">How to develop RxJS code</h2>



<h3 class="wp-block-heading">Mental modal for RxJS</h3>



<p>When working with RxJS it is important to have the right ideas about it. Seeing your code as a collection of streams of values can help. On that value stream, you can apply simple operators. Each stream you are dealing with can start, error out, or complete.</p>



<h3 class="wp-block-heading">Controlled step-by-step approach with verification</h3>



<p>Streams can be complex. That means they can have branches, multiple values arriving at different times, or nested structures. And that is why one has to build them step-by-step and include some verification into the process:</p>



<ul class="wp-block-list">
<li>You can effectively build streams by using TDD (Test-Driven Development)</li>



<li>Keep Observables as flat as possible (avoid nesting where possible)</li>



<li>Use Typescript properly to achieve additional safety and add more clarity inside streams</li>



<li>Understand compiler and error messages when something goes wrong</li>
</ul>



<h3 class="wp-block-heading">Use reactive code only when necessary</h3>



<p>You do not need to cover everything in RxJS. If something is not asynchronous, RxJS is the wrong choice. Keep your streams small and understandable and implement synchronous parts of your application with the right pattern, i.e. in synchronous code. Asynchronous code is hard enough on its own, despite RxJS.</p>



<h2 class="wp-block-heading">Example case</h2>



<p>Let us illustrate the above considerations in an example. In our demo case, we would like to load a Post entity based on a user action. To load that we also need to pass the user ID which is also offered as Observable. To spice things up, we also would like to load the post&#8217;s comments after the post is loaded. </p>



<h3 class="wp-block-heading">Setup testing properly</h3>



<p>The start is a simple test with an implementation you could choose to load the post. I have seen code similar to the following one many times. And I have seen developers struggling with it, being frustrated, and in the end, they blame RxJS.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">it('does not work', () =&gt; {
    const action$: Observable&lt;LoadPostsAction&gt; = of({ postId: 1 });
    const postService = new PostService();

    action$.pipe(
        map(action =&gt; action.postId),
        concatMap((postId) =&gt; postService.loadPost(postId)),
    ).subscribe({
        next: result =&gt; {
            expect(result).toEqual({id: 1, content: 'content of post 2'});
        },
    });
});</code></pre>



<p>If we run that test, all looks good:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="187" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_stream_test_passes_wrongly-1024x187.png" alt="All looks fine in the test." class="wp-image-2376" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_stream_test_passes_wrongly-1024x187.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_stream_test_passes_wrongly-300x55.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_stream_test_passes_wrongly-768x140.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_stream_test_passes_wrongly.png 1358w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The above code looks perfectly fine at first sight. But it is not! The test is green although the assertion is wrong (&#8220;post 2&#8221; although we would get &#8220;post 1&#8221; back in the result). Time for our first tip:</p>



<p><strong>☝</strong> <strong>Tip #1</strong>: Use TDD when developing RxJS streams and let the test first fail.</p>



<p>This means that in our case we first need a proper test setup. When testing asynchronous code in Jest (and alternatives), we need a callback. This is usually defined as &#8220;done&#8221; and we are then invoking the <code>done()</code> callback after asserting the outcome.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">it('does not work', (done) =&gt; {
    const action$: Observable&lt;LoadPostsAction&gt; = of({ postId: 1 });
    const postService = new PostService();

    action$.pipe(
        map(action =&gt; action.postId),
        concatMap((postId) =&gt; postService.loadPost(postId)),
    ).subscribe({
        next: result =&gt; {
            expect(result).toEqual({id: 1, content: 'content of post 2'});
            done();
        },
    });
});</code></pre>



<p>We have a failing test and are good to go and start extending our stream:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="248" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_test_correctly-1024x248.png" alt="" class="wp-image-2383" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_test_correctly-1024x248.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_test_correctly-300x73.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_test_correctly-768x186.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_test_correctly-1536x372.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_test_correctly.png 1592w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Of course, there are other testing approaches, e.g. marbles. But I don&#8217;t want to open that topic here. You can read my blog post about <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-testing-approaches-compared/">different RxJS testing approaches</a> if you are interested. Anyway, we need to be sure that we are testing the right thing and that is why our test should fail first, independent of the testing approach!</p>



<h3 class="wp-block-heading">Have the right mental model</h3>



<p>Before we move on let us spend some time to see how you as a developer can think about RxJS streams. The mental model I propose asks us to think about the values and how they stream through our program. We can illustrate this as follows:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="517" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_modal_1-1-1024x517.png" alt="" class="wp-image-2394" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_modal_1-1-1024x517.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_modal_1-1-300x151.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_modal_1-1-768x388.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_modal_1-1-1536x775.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_modal_1-1-2048x1033.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Values are green, source Observables blue (they are not the only Observables), and operators are indicated as rounded rectangles. Arrows show the flow of values.</p>



<p><strong>☝</strong> <strong>Tip #2</strong>: Remember that Observables are just values over time and those values flow through your program.</p>



<p>Now let us extend the functionality safely.</p>



<h3 class="wp-block-heading">Keep Observables as flat as possible</h3>



<p>Let us now tackle the next step of our functionality and load posts by user. For that, we need to take the current user ID into account. RxJS would allow nesting Observables. What you do then is branching of streams. But besides that, you also make code harder to read and harder to change. So it is not advisable to implement the new functionality like this (switchMap is nested inside concatMap):</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">action$.pipe(
    map(action =&gt; action.postId),
    concatMap((postId) =&gt; {
        return user.getCurrentUserId$().pipe(
            switchMap((userId) =&gt; postService.loadPost(postId, userId))
        );
    })
).subscribe({
    next: result =&gt; {
        expect(result).toEqual({id: 1, content: 'content of post 1'});
        done();
    },
});</code></pre>



<p>The <code>user.getCurrentUserId$()</code> Observable is used inside concatMap. This also means that we need to flatten the Observable of <code>loadPost</code> (more towards that in the next sub-section). A flat and clean structure is easier to handle:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">action$.pipe(
    map(action =&gt; action.postId),
    withLatestFrom(user.getCurrentUserId$()),
    concatMap((postId) =&gt; postService.loadPost(postId, null)),
).subscribe({
    next: result =&gt; {
        expect(result).toEqual({id: 1, content: 'content of post 1'});
        done();
    },
});</code></pre>



<p>Whenever the <code>action$</code> delivers a new value we want to combine it with the latest value of the current user&#8217;s ID. You see that we kept the null for <code>userId</code> in the <code>loadPost</code> method. This is because we want to first see what the compiler tells us (to showcase the importance of error messages).</p>



<h3 class="wp-block-heading">Understand error messages</h3>



<p>Error messages around RxJS can be hard to understand in the beginning. The last code example from above delivers the following on the <code>postId</code> parameter inside the <code>loadPost</code> method call:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">TS2345: Argument of type '[number, number]' is not assignable to parameter of type 'number'.</code></pre>



<p>The method expects a number but receives <code>[number, number]</code>. We have to understand <code><a href="https://rxjs.dev/api/index/function/pipe" target="_blank" rel="noreferrer noopener">pipe</a></code> here. Pipe is accepting operators as <code>UnaryFunction</code>s and forwards the output of one operator to the subsequent one. This passed output is one value, object, or array. Calling withLatestFrom changes the values in the stream and transforms <code>number</code> to <code>[number, number]</code>, representing the <code>postId</code> and <code>userId</code> in an array. Long story short, to fix the above TS2345 you have to adapt the code to consider the new input to the operator:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">action$.pipe(
    map(action =&gt; action.postId),
    withLatestFrom(user.getCurrentUserId$()),
    concatMap(([postId, userId]) =&gt; postService.loadPost(postId, userId)),
).subscribe({
    next: result =&gt; {
        expect(result).toEqual({id: 1, content: 'content of post 1'});
        done();
    },
});</code></pre>



<p>And please don&#8217;t use <code>(postId, userId)</code>. Something like this is not a <a href="https://rxjs.dev/api/index/interface/UnaryFunction" target="_blank" rel="noreferrer noopener">UnaryFunction</a> and is not going to work! This error message was not directly provided by RxJS but often occurs during RxJS development.</p>



<p>Another error message one often encounters is about higher-order Observables. Let us go back to the nested example from above. It is easy to miss the higher-order mapping operator, i.e. <code>switchMap</code>, and just use <code>map</code> in place of it:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">action$.pipe(
    map(action =&gt; action.postId),
    concatMap((postId) =&gt; {
        return user.getCurrentUserId$().pipe(
            map((userId) =&gt; postService.loadPost(postId, userId))
        );
    })
).subscribe({
    next: result =&gt; {
        expect(result).toEqual({id: 1, content: 'content of post 1'});
        done();
    },
});</code></pre>



<p>All looks good at first sight, but the test signals us:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="212" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_hot_to_build_streams_wrong_nesting-1024x212.png" alt="" class="wp-image-2397" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_hot_to_build_streams_wrong_nesting-1024x212.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_hot_to_build_streams_wrong_nesting-300x62.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_hot_to_build_streams_wrong_nesting-768x159.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_hot_to_build_streams_wrong_nesting-1536x318.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_hot_to_build_streams_wrong_nesting-2048x424.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We are expecting an object with fields like content and id. But what we are getting is not such an Object, but an Observable. Whenever you see this, you should check if you need to flatten another Observable. In our case, <code>switchMap</code> flattens an Observable.</p>



<p><strong>☝</strong> <strong>Tip #3:</strong> Try to understand each error message. They look cryptic and chaotic at times but are really not that hard to understand once you read them carefully. Go through them from top to bottom and focus on the bottom as the root cause is usually hidden there. During development with RxJS errors can happen and you should not guess, but read, and understand.</p>



<p>Update to our value stream model:</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;69e227dfb5858&quot;}" data-wp-interactive="core/image" data-wp-key="69e227dfb5858" class="wp-block-image size-large wp-lightbox-container"><img decoding="async" width="1024" height="442" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_model_2-1024x442.png" alt="" class="wp-image-2400" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_model_2-1024x442.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_model_2-300x130.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_model_2-768x332.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_model_2-1536x663.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_how_to_build_streams_mental_model_2-2048x884.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<h3 class="wp-block-heading">Use types</h3>



<p>As soon as values become more complex it can help to use types explicitly. True, the Typescript compiler can still help us and infer some types. Nevertheless specifying them explicitly can make it easier for us developers to understand. Extending by types will change our code to:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">action$.pipe(
    map((action: LoadPostAction) =&gt; action.postId),
    withLatestFrom(user.getCurrentUserId$()),
    concatMap(([postId, userId]: [number, number]) =&gt; postService.loadPost(postId, userId)),
).subscribe({
    next: (result: Post) =&gt; {
        expect(result).toEqual({id: 1, content: 'content of post 1'});
        done();
    },
});</code></pre>



<p>This makes extensions safer. For example, if we map the response of the post service to the content only (return string instead of Post), we would immediately notice because we also typed the result in the subscribe&#8217;s next handler. <br>The first one here looks okay to the compiler. Although we are passing string (the type of content) instead of Post.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">action$.pipe(
    map((action: LoadPostAction) =&gt; action.postId),
    withLatestFrom(user.getCurrentUserId$()),
    concatMap(([postId, userId]: [number, number]) =&gt; postService.loadPost(postId, userId)),
    map((response: Post) =&gt; response.content),
).subscribe({
    next: (result) =&gt; {
        expect(result).toEqual({id: 1, content: 'content of post 1'});
        done();
    },
});</code></pre>



<p>As soon as the next handler does have a type for its parameter, the compiler complains:</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;69e227dfb6359&quot;}" data-wp-interactive="core/image" data-wp-key="69e227dfb6359" class="wp-block-image size-large is-resized wp-lightbox-container"><img decoding="async" width="1024" height="275" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_now_to_build_streams_wrong_output_to_next-1-1024x275.png" alt="" class="wp-image-2405" style="width:839px;height:auto" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_now_to_build_streams_wrong_output_to_next-1-1024x275.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_now_to_build_streams_wrong_output_to_next-1-300x81.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_now_to_build_streams_wrong_output_to_next-1-768x207.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_now_to_build_streams_wrong_output_to_next-1-1536x413.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_now_to_build_streams_wrong_output_to_next-1-2048x551.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p>If you used RxJS before you probably have seen such error messages already. Important here is to understand that the error message is also considering the nesting. That is why we should always go to the innermost part of the message because that is usually the part the easiest to understand. In this case, &#8220;Type &#8216;string&#8217; is not assignable to type &#8216;Post'&#8221;. You see that TypeScript informs us quite well about the error. We expect a Post, but we are getting something of type string. The DX around error messages could be improved though.</p>



<p><strong>☝</strong> <strong>Tip #4: </strong>some extra types can help to make your code more robust and understand errors earlier. The compiler is a cheap and fast way to &#8220;test&#8221;, please use it! </p>



<p>Of course, there are cases where explicit types make no sense and we should really on the type inference instead.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>I hope those hints give you a better understanding and you can optimize your approach to RxJS development. Having the right mental model about your stream helps to understand what the operators do and what is happening to the values flowing through your program over time. </p>



<p></p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-how-to-build-streams/">RxJS Mastery &#8211; How to build streams</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; RxJS Patterns: a robust HTTP-based search input</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-rxjs-patterns-a-robust-http-based-search-input/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Mon, 19 Feb 2024 20:12:57 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2313</guid>

					<description><![CDATA[<p>Implement a search field with only 10 RxJS operators.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-rxjs-patterns-a-robust-http-based-search-input/">RxJS Mastery &#8211; RxJS Patterns: a robust HTTP-based search input</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="391" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_patterns_search_input-1-1024x391.png" alt="" class="wp-image-2315" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_patterns_search_input-1-1024x391.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_patterns_search_input-1-300x114.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_patterns_search_input-1-768x293.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_patterns_search_input-1-1536x586.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_patterns_search_input-1.png 1656w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>How can we implement a robust search input field in JavaScript that triggers HTTP requests to get search results? This is a common problem reoccurring in many web applications. RxJS offers a variety of operators to declaratively define what happens in case of events. A keystroke in an input field is an event. That is why we can nicely define the operations that should be executed (or not) in the case of such events. </p>



<h2 class="wp-block-heading">Aspects to consider for a search term input</h2>



<p>In the most basic form, a keystroke in a search box triggers an HTTP request on what is currently written in the input field, and the result is displayed as it comes back from the server. With that approach, the following problems can occur:</p>



<ul class="wp-block-list">
<li>⚠ If for every keystroke a request is triggered, too many HTTP requests may be executed and overload our backend systems.</li>



<li>😲 As distributed systems have varying response times, the request sequence A, B, and C can result for example in the response sequence B, C, and A. It could mean that the response to the request that was started first arrives last. This would confuse users.</li>



<li>🔄 A search term can change in quick succession and theoretically also end up on the same value again. Imagine, &#8220;RxJS&#8221;, &#8220;RxJS pat&#8221;, followed by &#8220;RxJS&#8221;. In such cases, we may not want to execute the search for &#8220;RxJS&#8221; again because it was just executed some milliseconds ago.</li>



<li>✅ Executing a search for any kind of search term, e.g. &#8220;R&#8221;, might be the wrong choice depending on the context. Starting the search after a certain word length can also here release some pressure from the backend systems and avoid unnecessary output to the user.</li>



<li>◝ As asynchronous operations are involved, there might be a requirement to inform the user somehow about ongoing operations.</li>



<li>⏳ In some cases the search could take a very long time and we would like to cancel it (automatically or by user interaction).</li>



<li>🚫 Especially when working with distributed systems, errors are likely to occur.</li>
</ul>



<p>We can address the problems above with the following potential solutions:</p>



<ul class="wp-block-list">
<li>⚠ Only after the user has stopped typing for some time, a request should be triggered. We need some sort of idle time detection after characters are entered.</li>



<li>😲 There should only be one running search request at a time. This search request should correspond to what is currently written in the search field.</li>



<li>🔄 When the input value doesn&#8217;t change compared to the last request, the request should not be executed.</li>



<li>✅ The search should only start after at least 3 characters were entered.</li>



<li>◝ A loading text should be shown underneath the search box during request execution.</li>



<li>⏳ After 7s a search request should be cancelled automatically.</li>



<li>🚫 Errors have to be caught and the user informed about them.</li>
</ul>



<p>These are some of the decisive aspects in the context of such a search field. In the remainder of this article, we are going to tackle them one by one with RxJS.</p>



<h2 class="wp-block-heading">How does RxJS address those aspects?</h2>



<h3 class="wp-block-heading">Basic setup and imperfect solution</h3>



<p>Let us first have a look at the demo case. To nicely demo a search, I&#8217;m using the post API of <a href="https://jsonplaceholder.typicode.com/" target="_blank" rel="noreferrer noopener">jsonplaceholder</a>. It supports a query parameter to filter by post title. This is perfect for our showcase. The search itself looks like this:</p>



<figure class="wp-block-image size-large my-4"><img decoding="async" width="1024" height="693" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_demo_1-1024x693.png" alt="" class="wp-image-2320" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_demo_1-1024x693.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_demo_1-300x203.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_demo_1-768x520.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_demo_1-1536x1039.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_demo_1.png 1706w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>As said, a basic search could look like the code below this paragraph. It just uses the operators <a href="https://rxjs.dev/api/index/function/fromEvent" target="_blank" rel="noreferrer noopener">fromEvent</a>,  <a href="https://rxjs.dev/api/operators/mergeMap" target="_blank" rel="noreferrer noopener">mergeMap</a>, and <a href="https://rxjs.dev/api/ajax/ajax" target="_blank" rel="noreferrer noopener">ajax</a>. From the <code>keyup</code> event of the search field, we&#8217;re accessing the target&#8217;s value. This value is the search term and it is passed as a query parameter to the API request. <code>Ajax</code> executes the API request, while <code>mergeMap</code> makes sure that the higher-order Observable is handled fine (<code>ajax</code> returns an Observable inside an Observable stream and therefore flatting is needed). Finally, in subscribe&#8217;s next handler, the response is accessed and put into some output container.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        mergeMap(event =&gt; ajax(`${apiUrl}?title_like=${event.target.value}`))
    )
    .subscribe({
        next: (httpEvent) =&gt; {
            const responseList = httpEvent.response;
            resultContainer.innerHTML = formatToHtml(responseList);
        }
    });</code></pre>



<p>When typing we see a lot of requests flying through our network tab:</p>



<figure class="wp-block-image size-large my-4"><img decoding="async" width="1024" height="468" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_unoptimised-1024x468.png" alt="Network requests in the dev tools when we haven't optimised the search input yet with RxJS." class="wp-image-2329" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_unoptimised-1024x468.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_unoptimised-300x137.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_unoptimised-768x351.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_unoptimised-1536x701.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_unoptimised-2048x935.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>5 requests triggered although I did not type slowly!</p>



<p>To address the limitations, RxJS offers a good palette of operators. And they are easy to understand too! Let us now go through the collected list from above one by one and show how RxJS comes into play. </p>



<h3 class="wp-block-heading">Only trigger requests after the user has stopped typing for some time</h3>



<p>The first operator we are going to use to optimize our solution is <a href="https://rxjs.dev/api/operators/debounceTime" target="_blank" rel="noreferrer noopener">debounceTime</a>. This operator only emits after a certain time span has passed without another source emission.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        mergeMap(event =&gt; ajax(`${apiUrl}?title_like=${event.target.value}`))
    )
    .subscribe({
        next: (httpEvent) =&gt; {
            const responseList = httpEvent.response;
            resultContainer.innerHTML = formatToHtml(responseList);
        }
    });</code></pre>



<p>A time span of 150 ms is usually a good choice. But this is a trade-off in the end between waiting time and the number of requests. Anyway, it already improves the situation in our network tab:</p>



<figure class="wp-block-image size-large my-4"><img decoding="async" width="1024" height="464" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_debounceTime-1024x464.png" alt="" class="wp-image-2331" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_debounceTime-1024x464.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_debounceTime-300x136.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_debounceTime-768x348.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_debounceTime-1536x695.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_requests_debounceTime-2048x927.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Have only one running request at a time</h3>



<p>As already mentioned above we need a higher-order mapping operator to handle the HTTP request. This is because ajax returns an Observable, but it would also be the case when we are using, e.g., Angular&#8217;s http implementation. RxJS offers the following higher-order mapping operators: <a href="https://rxjs.dev/api/operators/concatMap" target="_blank" rel="noreferrer noopener">concatMap</a>, <a href="https://rxjs.dev/api/operators/mergeMap" target="_blank" rel="noreferrer noopener">mergeMap</a>, <a href="https://rxjs.dev/api/operators/switchMap" target="_blank" rel="noreferrer noopener">switchMap</a>, and <a href="https://rxjs.dev/api/operators/exhaustMap" target="_blank" rel="noreferrer noopener">exhaustMap</a>. Their behavior is described in this <a href="https://ronnieschaniel.com/rxjs/operator-patterns/">article</a>.</p>



<p>The switch behavior always considers the newest inner Observable that was started and cancels older ones. This is perfect for our job. If a new input value from the search box arrives, a new inner Observable for the HTTP request is created. As an HTTP request is behind ajax&#8217;s Observable, the cancellation of it cancels the HTTP request.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        switchMap(event =&gt; ajax(`${apiUrl}?title_like=${event.target.value}`))
    )
    .subscribe({
        next: (httpEvent) =&gt; {
            const responseList = httpEvent.response;
            resultContainer.innerHTML = formatToHtml(responseList);
        }
    });</code></pre>



<p>So, do not be surprised to see canceled HTTP requests in the network tab (here we tried to provoke the situation by throttling the network and setting the &#8220;Slow 3G&#8221; in Google Chrome):</p>



<figure class="wp-block-image size-large my-4"><img decoding="async" width="1024" height="422" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_switchMap-1024x422.png" alt="RxJS switchMap is cancelling ongoing requests if new ones are arriving." class="wp-image-2334" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_switchMap-1024x422.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_switchMap-300x124.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_switchMap-768x317.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_switchMap-1536x633.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_switchMap-2048x844.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In some rare cases, another mapping operator might make sense:</p>



<ul class="wp-block-list">
<li>if requests are taking very long and we want them to be fully executed once started while still not overloading the server: exhaustMap. It will only run one request at a time.</li>



<li>every search should be triggered and executed in sequence because all results are interesting: concatMap.</li>
</ul>



<h3 class="wp-block-heading">Do not re-execute a request if the value for it has not changed</h3>



<p>RxJS provides <a href="https://rxjs.dev/api/operators/distinctUntilChanged" target="_blank" rel="noreferrer noopener">distinctUntilChanged</a> that only emits if the new value is different from the last one that made it through. To make that work we need to apply this distinct logic to the search term itself and not the event coming from the input field. Because the event is always going to be distinct. Luckily also here RxJS supports us with <a href="https://rxjs.dev/api/operators/pluck" target="_blank" rel="noreferrer noopener">pluck</a> and <a href="https://rxjs.dev/api/operators/filter">filter</a>. <code>Pluck</code> retrieves the value out of <code>event.target</code> while <code>filter</code> makes sure that only truthy values are arriving, i.e. no <code>undefined</code> is reaching that part of our Observable chain: </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        filter(Boolean),
        pluck('target', 'value'),
        distinctUntilChanged(),
        switchMap(searchTerm =&gt; ajax(`${apiUrl}?title_like=${searchTerm}`))
    )
    .subscribe({
        next: (httpEvent) =&gt; {
            const responseList = httpEvent.response;
            resultContainer.innerHTML = formatToHtml(responseList);
        }
    });</code></pre>



<p>The pluck also simplified the query parameter&#8217;s value and <code>event.target.value</code> is not needed anymore there. Instead of <code>pluck</code>, also <a href="https://rxjs.dev/api/operators/map" target="_blank" rel="noreferrer noopener">map</a> could have been an operator to access the target&#8217;s value. But pluck is a nice pick here because no null check is needed when traversing the object tree and we only need a single value.<br>As we are anyway already thinking about pluck, let us simplify the next handler by plucking the response field from the HTTP response:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        filter(Boolean),
        pluck('target', 'value'),
        distinctUntilChanged(),
        switchMap(searchTerm =&gt; ajax&lt;Post[]&gt;(`${apiUrl}?title_like=${searchTerm}`)),
        pluck('response')
    )
    .subscribe({
        next: (response) =&gt; {
            resultContainer.innerHTML = formatToHtml(response);
        }
    });</code></pre>



<h3 class="wp-block-heading">Only start executing requests after the user has entered at least three characters</h3>



<p>We have already seen the filter operator above and it will be used also in this case here. Furthermore, we would like to trim whitespaces because those are normally not interesting for a search. Hence <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim" target="_blank" rel="noreferrer noopener">trim</a> is coming into play, combined with RxJS&#8217;s map.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        filter(Boolean),
        pluck('target', 'value'),
        map(value =&gt; value.trim()),
        filter(searchTerm =&gt; searchTerm.length &gt; 2),
        distinctUntilChanged(),
        switchMap(searchTerm =&gt; ajax&lt;Post[]&gt;(`${apiUrl}?title_like=${searchTerm}`)),
        pluck('response')
    )
    .subscribe({
        next: (response) =&gt; {
            resultContainer.innerHTML = formatToHtml(response);
        }
    });</code></pre>



<h3 class="wp-block-heading">Display a loading spinner</h3>



<p>Here the debate begins. There exist many approaches to implement a loading spinner. Let us start with the following one:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        filter(Boolean),
        pluck('target', 'value'),
        map(value =&gt; value.trim()),
        filter(searchTerm =&gt; searchTerm.length &gt; 2),
        distinctUntilChanged(),
        switchMap(searchTerm =&gt; ajax&lt;Post[]&gt;(`${apiUrl}?title_like=${searchTerm}`).pipe(
            startWith({ response: { text: 'Loading...', type: 'LOADING_INDICATOR' }}),
        )),
        pluck('response')
    )
    .subscribe({
        next: (response) =&gt; {
            if (response?.type === 'LOADING_INDICATOR') {
                loadingIndicator.style.visibility = 'visible';
            } else {
                loadingIndicator.style.visibility = 'hidden';
                resultContainer.innerHTML = formatToHtml(response);
            }
        }
    });</code></pre>



<p>In that first version, we are piping the Ajax request into <a href="https://rxjs.dev/api/operators/startWith" target="_blank" rel="noreferrer noopener">startWith</a>. To follow the structure for <code>response</code> we deliver the text Loading&#8230; in an object together with the type <code>LOADING_INDICATOR</code>. The pluck works and in the next handler, we can then put the result into the <code>resultContainer</code> and change the visibility of the loading indicator when required. This might be an acceptable solution and it is even fully declarative in the upper part (in the pipe after <code>fromEvent</code>). However, in the next handler, we are going into an imperative mode (anyway due to the resultContainer&#8217;s innerHTML handling, but that is usually addressed through frameworks, e.g. async pipe in Angular).</p>



<p>An alternative is to tap <a href="https://rxjs.dev/guide/subject#behaviorsubject" target="_blank" rel="noreferrer noopener">BehaviorSubjects</a> from within the Observable chain. This variant is also somewhat imperative. But it gives us a second Observable to control the loading indicator:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const loadingSubject$ = new BehaviorSubject(false);
// some code to subscribe to the loadingSubject$ as Observable 
// and control the visibility of the loading element


tap(_ =&gt; loadingSubject$.next(true)),
switchMap(searchTerm =&gt; ajax&lt;Post[]&gt;(`${apiUrl}?title_like=${searchTerm}`)),
tap(_ =&gt; loadingSubject$.next(false)),</code></pre>



<p>Before and after the switchMap a <a href="https://rxjs.dev/api/operators/tap" target="_blank" rel="noreferrer noopener">tap</a> operator is placed to perform the side-effect of telling the BehaviorSubject whether to show something or not. </p>



<p>Both variants have their drawbacks. I&#8217;m still looking for a good solution here.</p>



<h3 class="wp-block-heading">Cancel a request automatically after 7 seconds</h3>



<p>Last but not least we need to talk about the not-so-happy cases. Requests can time out or other errors can happen. We would like to inform our users about such cases. Therefore after 7 seconds of no response, an error message should be displayed and the ongoing request be cancelled. Yet another specific operator comes to the rescue. This time it is <a href="https://rxjs.dev/api/operators/timeout" target="_blank" rel="noreferrer noopener">timeout</a>.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        filter(Boolean),
        pluck('target', 'value'),
        map(value =&gt; value.trim()),
        filter(searchTerm =&gt; searchTerm.length &gt; 2),
        distinctUntilChanged(),
        tap(_ =&gt; loadingSubject$.next(true)),
        switchMap(searchTerm =&gt; ajax&lt;Post[]&gt;(`${apiUrl}?title_like=${searchTerm}`).pipe(
            timeout(REQUEST_TIMEOUT))
        ),
        tap(_ =&gt; loadingSubject$.next(false)),
        pluck('response')
    )
    .subscribe({
        next: (response) =&gt; {
            resultContainer.innerHTML = formatToHtml(response);
        }
    });</code></pre>



<p>The <code>timeout</code> operator is defined in the pipe after <code>ajax</code>. This is because we want to timeout if the request is too slow and we would like the request to be canceled in such cases. As a consequence, we can see the following in our browser when the response does not arrive in time (<code>REQUEST_TIMEOUT</code> is the timeout in milliseconds).</p>



<figure class="wp-block-image size-large my-4"><img decoding="async" width="1024" height="116" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_timeout-1024x116.png" alt="" class="wp-image-2350" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_timeout-1024x116.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_timeout-300x34.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_timeout-768x87.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_timeout-1536x174.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_network_request_timeout-2048x232.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Let us optimize that in the next section where we catch uncaught things.</p>



<h3 class="wp-block-heading">Show an error message when the search request fails</h3>



<p>If we would like to catch any errors, you might have already guessed the operator for that. We apply <a href="https://rxjs.dev/api/operators/catchError" target="_blank" rel="noreferrer noopener">catchError</a>:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">fromEvent(searchField, 'keyup')
    .pipe(
        debounceTime(150),
        filter(Boolean),
        pluck('target', 'value'),
        map(value =&gt; value.trim()),
        filter(searchTerm =&gt; searchTerm.length &gt; 2),
        distinctUntilChanged(),
        tap(_ =&gt; loadingSubject$.next(true)),
        switchMap(searchTerm =&gt; ajax&lt;Post[]&gt;(`${apiUrl}?title_like=${searchTerm}`).pipe(
            timeout(REQUEST_TIMEOUT))
        ),
        tap(_ =&gt; loadingSubject$.next(false)),
        pluck('response'),
        catchError(error =&gt; {
            loadingSubject$.next(false);
            displayError(error.message);
            return [];
        }),
    )
    .subscribe({
        next: (response) =&gt; {
            resultContainer.innerHTML = formatToHtml(response);
        }
    });</code></pre>



<p>The nice thing about the catch is that we can place it at the end and it will handle any error that happens in the stream. The default value empty array is returned. With a little bit of CSS and HTML, it looks like in the image below. The error is shown while the loading indicator is hidden again.</p>



<figure class="wp-block-image size-large my-4"><img decoding="async" width="1024" height="275" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_error-1024x275.png" alt="" class="wp-image-2351" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_error-1024x275.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_error-300x81.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_error-768x206.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_error-1536x412.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_search_input_error.png 1542w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In the course of this article, we have used 10 different operators. And I could even think of some more to apply in that context, e.g. <a href="https://rxjs.dev/api/operators/retry">retry</a> or <a href="https://rxjs.dev/api/operators/finalize">finalize</a>. This is probably where some people start to complain about how hard to learn RxJS is. But, please keep in mind that every operator is designed for its purpose and does its specific task well! This allows us to combine different operators as we wish, to specify the behavior of our program from simple building blocks. The nice thing about all that: you can declaratively program and define what should happen. </p>



<p>Please note, that the TypeScript usage in these examples was not ideal. More type safety should be added. But the focus here was on RxJS. If someone has a good approach for the loading indicator, let me know!</p>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-rxjs-patterns-a-robust-http-based-search-input/">RxJS Mastery &#8211; RxJS Patterns: a robust HTTP-based search input</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; #71 Mathematical and Aggregator Operators</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-71-mathematical-and-aggregator-operators/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 18 Feb 2024 15:40:46 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2300</guid>

					<description><![CDATA[<p>Mathematical and aggregator operators are other utility operators.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-71-mathematical-and-aggregator-operators/">RxJS Mastery &#8211; #71 Mathematical and Aggregator Operators</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="393" src="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_71_mathematical_and_aggregator_operators-1024x393.png" alt="" class="wp-image-2302" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_71_mathematical_and_aggregator_operators-1024x393.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_71_mathematical_and_aggregator_operators-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_71_mathematical_and_aggregator_operators-768x295.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_71_mathematical_and_aggregator_operators-1536x589.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/02/rxjs_71_mathematical_and_aggregator_operators.png 1658w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>RxJS provides some handy utility operators. <a href="https://rxjs.dev/api/operators/max" target="_blank" rel="noreferrer noopener">Count</a>, <a href="https://rxjs.dev/api/operators/max">max</a>, <a href="https://rxjs.dev/api/operators/min" target="_blank" rel="noreferrer noopener">min</a>, and <a href="https://rxjs.dev/api/operators/reduce" target="_blank" rel="noreferrer noopener">reduce</a> are the ones we have a look at in this article.</p>



<h2 class="wp-block-heading">RxJS count returns the number of values</h2>



<p>The RxJS count operator emits the number of values once the source completes. Below the source emits the values a, b, and c. This is why <code>count</code> is returning 3 at the 4th timeframe (together with the completion).</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold('abc|').pipe(
    count()
);

expectObservable(result$).toBe(
    '---(d|)', { d: 3 }
);</code></pre>



<p>The operator also works with a condition. This gives us the possibility to count the values matching a predicate. In the below example, we are counting the numbers greater than 2. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number&gt;('1234|').pipe(
    count(v =&gt; v &gt; 2)
);

expectObservable(result$).toBe(
    '----(d|)', { d: 2 }
);</code></pre>



<h2 class="wp-block-heading">RxJS max and min</h2>



<p>Also for the RxJS max and min operators the completion time of the source Observable is decisive. Because only at that time all values are known and, as the name suggests, the maximal or minimal value is emitted. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number&gt;('8923402|').pipe(
    max()
);

expectObservable(result$).toBe(
    '-------(r|)', { r: '9' }
);</code></pre>



<p>Similarly, the number 0 is found when applying <code>min</code>:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number&gt;('8923402|').pipe(
    min()
);

expectObservable(result$).toBe(
    '-------(r|)', { r: '0' }
);</code></pre>



<p>The operator works by default with numbers but also accepts a comparator function to compare objects. Let us try to find the cheapest product:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">type product = { name: string, price: number }
const result$ = cold&lt;product&gt;('abc|',
    {
        a: { name: 'Book', price: 10 },
        b: { name: 'Video', price: 15 },
        c: { name: 'Course', price: 20 },
    }).pipe(
    min((a, b) =&gt; a.price &lt; b.price ? -1 : 1)
);

expectObservable(result$).toBe(
    '---(r|)', { r: { name: 'Book', price: 10 } }
);</code></pre>



<p>The cheapest one is the Book with a price of 10.</p>



<h2 class="wp-block-heading">RxJS reduce</h2>



<p>Most of you probably know the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce" target="_blank" rel="noreferrer noopener">reduce</a> function typically available in most languages. Reduce applies an accumulator function on each value which allows to combining past values with new ones. Optionally a seed can be specified as a starting value. <br>In our example, we simply sum up numbers and start with a seed value of 0:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number&gt;('8923402|').pipe(
    reduce((a, b) =&gt; Number(a) + Number(b), 0)
);

expectObservable(result$).toBe(
    '-------(r|)', { r: 28 }
);</code></pre>



<p>As with every operator in this article, the emission happens once the source completes.</p>



<h2 class="wp-block-heading">Exercise for the RxJS mathematical and aggregator operators 💪</h2>



<p>Build RxJS <code>reduce</code> by combining the <a href="https://ronnieschaniel.com/rxjs/rxjs-scan-operator/">scan</a> operator with the <a href="https://ronnieschaniel.com/rxjs/rxjs-last/">last</a> operator.</p>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-71-mathematical-and-aggregator-operators/">RxJS Mastery &#8211; #71 Mathematical and Aggregator Operators</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; #70 Conditional and Boolean Operators</title>
		<link>https://ronnieschaniel.com/rxjs/conditional-and-boolean-operators/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 28 Jan 2024 15:57:20 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2285</guid>

					<description><![CDATA[<p>Filter some values or check states.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/conditional-and-boolean-operators/">RxJS Mastery &#8211; #70 Conditional and Boolean Operators</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="393" src="https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_70_mastery_conditional_and_boolean_operators-1024x393.png" alt="RxJS conditional and boolean operators" class="wp-image-2287" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_70_mastery_conditional_and_boolean_operators-1024x393.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_70_mastery_conditional_and_boolean_operators-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_70_mastery_conditional_and_boolean_operators-768x294.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_70_mastery_conditional_and_boolean_operators-1536x589.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_70_mastery_conditional_and_boolean_operators.png 1654w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>RxJS offers a variety of conditional and boolean operators. Let us have a look at <a href="https://rxjs.dev/api/operators/defaultIfEmpty">defaultIfEmpty</a>, <a href="https://rxjs.dev/api/operators/every">every</a>, <a href="https://rxjs.dev/api/operators/find">find</a>, <a href="https://rxjs.dev/api/operators/findIndex">findIndex</a>, and <a href="https://rxjs.dev/api/operators/isEmpty">isEmpty</a>.</p>



<h2 class="wp-block-heading">RxJS defaultIfEmpty for default values</h2>



<p>Observables wrap asynchronous operations that might not be 100% reliable. This means they sometimes either do not deliver a value or do not return it in time. In the best case, it is just a missing value, in the worst the Observables chain requires a value or would through an error otherwise. That is where defaultIfEmpty comes to the rescue. <br>If the Observable completes without emitting any next value, defaultIfEmpty delivers a specified value.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold('---|').pipe(
    defaultIfEmpty(0)
);

expectObservable(result$).toBe(
    '---(d|)',
    {
        d: 0,
    }
);</code></pre>



<p>Of course, the default value can only be delivered on the 4th time frame when the original Observable has completed.</p>



<h2 class="wp-block-heading">RxJS every to check the whole sequence</h2>



<p>The RxJS every operator checks all the values that are emitted. If one value violates the condition specified, false is emitted and the Observable completes. If all values pass, true is emitted with completing.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number&gt;('24678|').pipe(
    every(v =&gt; v % 2 === 0)
);

expectObservable(result$).toBe(
    '---(f|)',
    {
        f: false,
    }
);</code></pre>



<p>In the below example, all values return true for the condition:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('2468|').pipe(
    every(v => v % 2 === 0)
);

expectObservable(result$).toBe(
    '----(t|)',
    {
        t: true,
    }
);</code></pre>



<h2 class="wp-block-heading">RxJS find to emit a single value matching a condition</h2>



<p>Find checks every value in the stream and emits the first one for which the specified condition is true. At the same time, it sends a complete notification. The condition in the below example is checking for multiples of 3. In the sequence of numbers from 1 to 9, the first value that fulfills the condition is 3. Hence, 3 is emitted and the stream completes.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('123456789|').pipe(
    find(v => v % 3 === 0)
);

expectObservable(result$).toBe(
    '--(v|)', { v: "3" }
);</code></pre>



<p>If no value fulfills the condition and the source completes, <code>undefined</code> is emitted. In the below test, we are trying to find an even number in a sequence of odd numbers:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('1357|').pipe(
    find(v => v % 2 === 0)
);

expectObservable(result$).toBe(
    '----(u|)', { u: undefined }
);</code></pre>



<h2 class="wp-block-heading">RxJS findIndex for finding the index</h2>



<p>The <code>findIndex</code> operator works like <code>find</code>, but emits only the index of the first found value. So, if we&#8217;re taking the above example of the previous section, the index 2 is emitted and not the value 3:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('123456789|').pipe(
    findIndex(v => v % 3 === 0)
);

expectObservable(result$).toBe(
    '--(i|)', { i: 2 }
);</code></pre>



<p>Please note that the case where no value is found does not end up with <code>undefined</code>. The value <code>-1</code> is emitted instead, following the logic of javascript&#8217;s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex" target="_blank" rel="noreferrer noopener">findIndex</a>.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('1357|').pipe(
    findIndex(v => v % 2 === 0)
);

expectObservable(result$).toBe(
    '----(i|)', { i: -1 }
);</code></pre>



<h2 class="wp-block-heading">RxJS isEmpty emits true if the source is not emitting any values</h2>



<p>The final operator that we are looking into in the area of conditional and boolean operators, is the <code>isEmpty</code> operator. As the name suggests, it checks the source for any values. If no values are emitted by the source, the value <code>true</code> is emitted and the Observable completes.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('----|').pipe(
    isEmpty()
);

expectObservable(result$).toBe(
    '----(t|)', { t: true }
);</code></pre>



<p>Once a value is found, the stream completes and emits <code>false</code>:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold&lt;number>('---123|').pipe(
    isEmpty()
);

expectObservable(result$).toBe(
    '---(f|)', { f: false }
);</code></pre>



<h2 class="wp-block-heading">Exercise for the RxJS conditional and boolean operators 💪</h2>



<p>Prevent the EmptyError in the below Observable chain. Deliver the value 0 instead.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold('---|').pipe(
    first(),
);

expectObservable(result$).toBe(
    '---(d|)',
    {
        d: 0,
    }
);</code></pre>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/conditional-and-boolean-operators/">RxJS Mastery &#8211; #70 Conditional and Boolean Operators</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; More safety for RxJS through eslint</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-more-safety-for-rxjs-through-eslint/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Fri, 19 Jan 2024 09:35:27 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2266</guid>

					<description><![CDATA[<p>Avoid common mistakes through automated checks.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-more-safety-for-rxjs-through-eslint/">RxJS Mastery &#8211; More safety for RxJS through eslint</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="391" src="https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_mastery_eslint-1024x391.png" alt="" class="wp-image-2268" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_mastery_eslint-1024x391.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_mastery_eslint-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_mastery_eslint-768x293.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_mastery_eslint-1536x587.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_mastery_eslint.png 1654w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>People often complain that it can be hard to use RxJS in the right way. There is a feeling that memory leaks are always around the corner. With the recent introduction of Signals in Angular the RxJS situation is even more unsure. However, RxJS is here to stay! To avoid RxJS pitfalls, understanding the concepts is crucial. Besides that there is also some help we can get in through RxJS eslint. In this post, I show various rules.</p>



<h2 class="wp-block-heading">Setup of RxJS with eslint</h2>



<p>There is an <a href="https://github.com/cartant/eslint-plugin-rxjs" target="_blank" rel="noreferrer noopener">eslint-plugin-rxjs</a> available. To install the package you first need to install the ESLint TypeScript parser followed by the package itself:</p>



<pre class="wp-block-code"><code class="">npm install @typescript-eslint/parser --save-dev
npm install eslint-plugin-rxjs --save-dev</code></pre>



<p>In the <code>.eslintrc.js</code> file in your project you can configure the plugin (code taken from <a href="https://github.com/cartant/eslint-plugin-rxjs" target="_blank" rel="noreferrer noopener">https://github.com/cartant/eslint-plugin-rxjs</a>):</p>



<pre title="" class="wp-block-code"><code lang="javascript" class="language-javascript">const { join } = require("path");

module.exports = {
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: 2019,
    project: join(__dirname, "./tsconfig.json"),
    sourceType: "module"
  },
  plugins: ["rxjs"],
  extends: [],
  rules: {
    "rxjs/no-async-subscribe": "error",
    "rxjs/no-ignored-observable": "error",
    "rxjs/no-ignored-subscription": "error",
    "rxjs/no-nested-subscribe": "error",
    "rxjs/no-unbound-methods": "error",
    "rxjs/throw-error": "error"
  }
};</code></pre>



<p>Alternatively, the recommended configuration can be used. This enables some of the rules that are likely to be relevant for most usages.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">const { join } = require("path");

module.exports = {
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: 2019,
    project: join(__dirname, "./tsconfig.json"),
    sourceType: "module"
  },
  extends: ["plugin:rxjs/recommended"],
};</code></pre>



<p>For Angular projects, there is another plugin (<a href="https://github.com/cartant/eslint-plugin-rxjs-angular" target="_blank" rel="noreferrer noopener">eslint-plugin-rxjs-angular</a>) available.</p>



<h2 class="wp-block-heading">ESLint in action</h2>



<p>We are creating a task in the package.json to execute eslint for our project. Here we are only interested in a certain directory.</p>



<pre class="wp-block-code"><code class="">"lint": "npx eslint src/rxjs_eslint/**/*.ts"</code></pre>



<p>This allows us to run the lint functionality and see the violations. If we would have a file like the following:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { of } from 'rxjs';


// finnish notation violation
const obs = of(1);

// correct example
const finnish$ = of(1);</code></pre>



<p>The rule <code>"rxjs/finnish": "error"</code> sees an error and shows us the file and line where we violate the rule:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="305" src="https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_eslint_finnish-1024x305.png" alt="" class="wp-image-2276" srcset="https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_eslint_finnish-1024x305.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_eslint_finnish-300x89.png 300w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_eslint_finnish-768x229.png 768w, https://ronnieschaniel.com/wp-content/uploads/2024/01/rxjs_eslint_finnish.png 1028w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Deep dive into some rules</h2>



<p>A full list of rules is available on the official <a href="https://github.com/cartant/eslint-plugin-rxjs?tab=readme-ov-file#rules" target="_blank" rel="noreferrer noopener">GitHub</a> page of the plugin. Nevertheless, I want to show some interesting ones in detail and explain which situations we can avoid thanks to them.</p>



<h3 class="wp-block-heading">No nested subscribe</h3>



<p>A subscribe within a subscribe is bad practice. It breaks the stream and can lead to memory leaks. It is also kind of imperative instead of the declarative way that RxJS nicely provides for us. Luckily eslint-plugin-rxjs offers a rule:</p>



<pre class="wp-block-code"><code lang="json" class="language-json">"rxjs/no-nested-subscribe": "error"</code></pre>



<p>Like that, we would receive a reminder if a nested subscription appears in our code:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">of(1).subscribe({
    next: value =&gt; {
        of(2).pipe(
            map(inner =&gt; inner + value)
        ).subscribe(console.log)
    }
});</code></pre>



<p>Usually, we can handle such a situation by just pulling the operators up and flattening the higher-order Observable:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">of(1).pipe(
    concatMap(value =&gt; of(2)
        .pipe(
            map(inner =&gt; inner + value))
    )
).subscribe(console.log);</code></pre>



<p>Of course, also other higher-order Observable mapping operators than concatMap can be used.</p>



<h3 class="wp-block-heading">No ignored subscription</h3>



<p>When we subscribe in RxJS, we should also unsubscribe to stop the async operation or clean up. To unsubscribe we need at least to assign the subscription somewhere or use an operator like take that unsubscribes.</p>



<p>RxJS eslint offers the &#8220;no-ignored-subscription&#8221; rule that fires if a subscription is neither assigned to a variable or property nor passed to a function. The following code would violate the rule:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">interval(1e3).pipe().subscribe(
    (value) =&gt; console.log(value)
);</code></pre>



<p>However, also using a take operator will still fire the rule. This is kind of okay because we don&#8217;t know whether the Observable will emit any value and ever reach the take operator the required times. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">interval(1e3).pipe(take(1)).subscribe(
    (value) =&gt; console.log(value)
);</code></pre>



<p>Hence, it is better in my opinion to use the &#8220;no-ignored-subscription&#8221; just as a warning and not fail the linting completely. This can be configured in the .eslintrc.js file:</p>



<pre class="wp-block-code"><code lang="json" class="language-json">"rxjs/no-ignored-subscription": "warn"</code></pre>



<h3 class="wp-block-heading">No internal</h3>



<p>The &#8220;no-internal&#8221; rule is again more obvious and straightforward. We do not want to rely on internals:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { of } from 'rxjs/internal/observable/of';

import { of } from 'rxjs';</code></pre>



<p>This results in an error because of the import on line 1. </p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">1:20  error  RxJS imports from internal are forbidden  rxjs/no-internal</code></pre>



<p>Preferable is the import on line 3.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Especially in larger code bases, linting is going to help ensure consistency. As always with rules a discussion should happen about which ones to use. Explaining which problems a certain rule is preventing, can help to get it in.</p>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always you can find the code examples on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-more-safety-for-rxjs-through-eslint/">RxJS Mastery &#8211; More safety for RxJS through eslint</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; Testing approaches compared</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-testing-approaches-compared/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Fri, 29 Dec 2023 20:22:03 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2171</guid>

					<description><![CDATA[<p>How do the setup and verification steps of the tests look like?</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-testing-approaches-compared/">RxJS Mastery &#8211; Testing approaches compared</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="395" src="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_testing_approaches_compared-1024x395.png" alt="Lesson title image for RxJS testing approaches compared." class="wp-image-2175" srcset="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_testing_approaches_compared-1024x395.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_testing_approaches_compared-300x116.png 300w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_testing_approaches_compared-768x296.png 768w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_testing_approaches_compared-1536x592.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_testing_approaches_compared.png 1654w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>There are many options out there when testing reactive code based on RxJS. Hence, especially for beginners, it can be hard to choose between all the RxJS testing approaches. This leads to frustration and in the worst case, the code remains untested. In this article, I want to show different patterns and their problems. </p>



<p>Please note, that the mentioned code is reduced to the minimum to bring the necessary points across. The full tests can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons/tree/main/src/rxjs_testing_approaches_compared" target="_blank" rel="noreferrer noopener">GitHub</a>. Also, we are only scratching the surface of various testing approaches and mainly checking setup and verification.</p>



<p>After the introduction of an example code to be tested you will see:</p>



<ol class="list-decimal list-inside mt-2 wp-block-list">
<li>Mocking with the <em>of</em> operator and subscribing explicitly</li>



<li>Using BehaviorSubject for mocking</li>



<li>RxJS marbles for mocks and outcomes</li>



<li>Auto-spies for setup and observer-spy to verify values</li>
</ol>



<h2 class="wp-block-heading">Example: combining asynchronous resources on an action</h2>



<p>Sometimes you need to load something from an HTTP service and based on the result you retrieve something related to that. Finally, everything should be emitted together. The resources to load are based on values emitted by an <em>Observable</em>. And to make it even more reactive the trigger to load things is also an <em>Observable</em> emitting a value. This is going to be the scenario for our tests.</p>



<p>For our example, you can think of a &#8220;Load more&#8221; button on a feed that loads more posts and their associated comments. An action is triggered to load posts followed by their comments. The action itself tells us which posts to load. So, the code may look like the following:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">loadPostAction$.pipe(
    map(action =&gt; action.postIds),
    concatMap((postIds: number[]) =&gt;
        from(postIds).pipe(
            mergeMap(postId =&gt; postService.loadPost(postId)),
        ),
    ),
    mergeMap(post =&gt; commentService.loadComments(post.id).pipe(
        map(comments =&gt; ({ ...post, comments: comments }))
    )),
);</code></pre>



<p>ⓘ Some explanations:</p>



<ul class="wp-block-list">
<li><code>loadPostAction$</code> is an <em>Observable</em> emitting an action that contains the IDs of those posts that we want to load.</li>



<li><code>loadPost</code> of the <code>postService</code> is a method to call an HTTP service that returns a single post. It accepts a post ID as input.</li>



<li>The <code>commentService</code> offers a method <code>loadComments</code>. It accepts a post ID and returns an array of comments as <em>Observable</em> for that post.</li>
</ul>



<p>For testing, we set up some basic mocks. The content of the post is going to contain &#8220;content of post&#8221; followed by the post ID. For the comments, we want to return an array of two comments mentioning a static text alongside the post ID. If we run the above code in the test context, we expect something like the below output: </p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">{
  id: 5,
  content: 'content of post 5',
  comments: [ 'first comment (5)', 'another comment (5)' ]
}

{
  id: 6,
  content: 'content of post 6',
  comments: [ 'first comment (6)', 'another comment (6)' ]
}

{
  id: 7,
  content: 'content of post 7',
  comments: [ 'first comment (7)', 'another comment (7)' ]
}</code></pre>



<p>For each post, the comments are loaded and assigned to the <code>Post</code> object. There are better ways to implement the above functionality. And one would maybe structure the code differently. However, it is sufficient as an example for us. We are ready to go and explore the first option for testing.</p>



<h2 class="wp-block-heading">1. Mocking with the <em>of</em> operator and subscribing explicitly</h2>



<p>Our code is based on <em>Observables</em>. Wouldn&#8217;t it be great, to just use the RxJS <a href="https://rxjs.dev/api/index/function/of" target="_blank" rel="noreferrer noopener"><em>of</em></a> operator to set those <em>Observable</em> values? Let&#8217;s try.</p>



<p>We define the <code>loadPostAction$</code>, <code>loadPost</code> and <code>loadComments</code> as follows:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const loadPostAction$: Observable&lt;LoadPostsAction&gt; = of({ postIds: [5,6,7] });
const loadPostMock = jest.spyOn(postService, 'loadPost');
const loadCommentsMock = jest.spyOn(commentService, 'loadComments');

loadPostMock.mockImplementation((postId: number): Observable&lt;Post&gt; =&gt; of(
    {id: postId, content: `content of post ${postId}` }
));
loadCommentsMock.mockImplementation((postId: number): Observable&lt;string[]&gt; =&gt; of(
    [
        `first comment (${postId})`,
        `another comment (${postId})`
    ]
));</code></pre>



<p>The action is an <em>Observable</em> based on <em>of</em>, while the two service methods are mocked with the help of jest. In the end also they are based on the <em>of</em> operator. Now we can assign the <code>loadPostAction$.pipe...</code> to a <code>result$</code> <em>Observable</em>, explicitly subscribe, push the values into an output array, and verify:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">// const result$ = loadPostAction$.pipe( ...
//    map... etc.

const output: Post[] = [];

result$.subscribe({
    next: post =&gt; output.push(post),
});

expect(output).toEqual(expectedPosts);</code></pre>



<p>Testing with <code>of</code> and <code>subscribe</code> is more or less straightforward. However, it has the following disadvantages:</p>



<ul class="wp-block-list">
<li>⏱ There is no notion of time to specify easily at what exact moment values are emitted. Similarly, it is harder to assert when values arrive in the final result <em>Observable</em>. </li>



<li>⏳ Sometimes time-based <em>Observables</em>, like <a href="https://rxjs.dev/api/index/function/interval" target="_blank" rel="noreferrer noopener"><em>interval</em></a>, are used in the code under test. In this case, the run time of the test is most likely going to be longer than just a few milliseconds.</li>



<li>✍ Generally setting up <em>subscribe</em> and pushing results to an array (if necessary) can be tedious. If you want to test <em>error</em> and <em>complete</em> notifications, it is even more work.</li>



<li>❗Subscribing might also cause <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-memory-leaks/">memory leaks</a> in some cases.</li>
</ul>



<p>On to the next section where the setup part is modified slightly.</p>



<h2 class="wp-block-heading">2. Using <strong>BehaviorSubject</strong> for mocking</h2>



<p>In Section 1 the <em>Observables</em> were defined using the <em>of</em> operator that emits synchronously:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const loadPostAction$: Observable&lt;LoadPostsAction&gt; = of({ postIds: [5,6,7] });</code></pre>



<p>This is not very convenient when you want to see different values separated by time emitted during a single test. This is where <em>BehaviorSubject</em> comes into play. As you probably know, a <em><a href="https://rxjs.dev/guide/subject" target="_blank" rel="noreferrer noopener">Subject</a></em> in RxJS is an <em>Observable</em> and an <em>Observer</em> at the same time. Therefore it offers a <em>next</em> method to push some values.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const loadPostAction$: BehaviorSubject&lt;LoadPostsAction&gt; = new BehaviorSubject({ postIds: [5,6,7] });</code></pre>



<p>Thanks to the Subject, we can test how the code behaves after the loadPostAction is triggered with some new post IDs.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">// still subscribing to result$ and pushing to an output array 

// just pushing some new values
loadPostAction$.next({ postIds: [8,9,10] });

expect(output[3].id).toEqual(8);
expect(output[4].id).toEqual(9);
expect(output[5].id).toEqual(10);</code></pre>



<p>After having loaded the posts with IDs 5, 6, and 7, we are interested in the three next posts (8, 9, and 10). To keep things simple, the assertion here is done on the <code>id</code> field. This variant with <em>BehaviorSubject</em> works too, but it still feels a bit awkward:</p>



<ul class="wp-block-list">
<li>✓ We can push different values for an involved Observable.</li>



<li>⏱ There is still no notion of time (which might be ok for simple tests).</li>



<li>📏 The verification phase wasn&#8217;t changed at all and still involves subscribing explicitly and checking the content of an array.</li>
</ul>



<h2 class="wp-block-heading">3. RxJS marbles for mocks and outcomes</h2>



<p>RxJS offers <a href="https://rxjs.dev/guide/testing/marble-testing" target="_blank" rel="noreferrer noopener">marble testing</a>. To apply it, one has to first understand the marble syntax. Through the helper methods, <em>hot</em> and <em>cold</em> Observables can be created that follow a certain timing. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const loadPostAction$: Observable&lt;LoadPostsAction&gt; = hot('-a-----b-------|', {
    a: { postIds: [5,6,7] },
    b: { postIds: [8,9,10] },
});
const loadPostMock = jest.spyOn(postService, 'loadPost');
const loadCommentsMock = jest.spyOn(commentService, 'loadComments');

loadPostMock.mockImplementation((postId: number): Observable&lt;Post&gt; =&gt; cold('-r|', {
    r: {id: postId, content: `content of post ${postId}`}
}));
loadCommentsMock.mockImplementation((postId: number): Observable&lt;string[]&gt; =&gt; cold('--r|', {
    r: [
        `first comment (${postId})`,
        `another comment (${postId})`
    ]
}));</code></pre>



<p>ⓘ Some notes to the above setup:</p>



<ul class="wp-block-list">
<li><code>loadPostAction$</code> was defined as a hot <em>Observable</em>. Already there we are defining the emissions over time (IDs 8, 9, 10 coming 6 time frames after the first batch of IDs).</li>



<li>For the service&#8217;s methods, we again spy on the service classes and mock the implementation. Here the return values are based on cold <em>Observables</em> involving one or two frames of waiting time respectively.</li>
</ul>



<p>Also for the verification step, marbles offer us a convenient method <em>expectObservable</em>. It lets us define the expected output also as a marble diagram, i.e. as a string with time frames and emitted values.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">expectObservable(result$).toBe('----(abc)-(def)|', {
    a: {
        id: 5,
        content: 'content of post 5',
        comments: [ 'first comment (5)', 'another comment (5)' ]
    },
    ...</code></pre>



<p>On frame 4 the first post with ID 5 arrives in the output together with two other posts (ID 6 and 7). On frame 10 the next group of 3 are emitted. Please note that parentheses also move the time forward. Finally, the | sign denotes completion. This is really cool if we want to test the exact timing. For our example though it wouldn&#8217;t matter that much. We are just interested in receiving posts. </p>



<p>Let us pin down the most important points for marble testing</p>



<ul class="wp-block-list">
<li>⏱ Marbles testing is a good choice if the timing of the <em>Observables</em> is important.</li>



<li>😃 Setup and verification can both be done in a similar way.</li>



<li>✓ It not only allows testing the next notification but also testing errors and especially completion is rather easy.</li>



<li>✍ Sometimes it can be tedious to find the exact time span for the result verification. You find yourself adjusting frame by frame.</li>



<li>😤 Especially the time progression due to the parentheses is annoying and can prevent testing certain scenarios.</li>



<li>🙄 The setup in the tests can be a bit tedious, especially when using the plain test scheduler. There are libraries though for <a href="https://github.com/just-jeb/jest-marbles" target="_blank" rel="noreferrer noopener">jest</a> and <a href="https://github.com/CodeSequence/jasmine-marbles" target="_blank" rel="noreferrer noopener">jasmine</a>. </li>
</ul>



<h2 class="wp-block-heading">4. Auto-spies for setup and observer-spy to verify values</h2>



<p>For some devs, the marbles syntax is hard to get or the timing of emissions is not important for the code under test. In that case, <a href="https://github.com/hirezio/observer-spy" target="_blank" rel="noreferrer noopener">observer-spy</a> might be a better choice for testing RxJS. It usually is combined with <a href="https://github.com/hirezio/auto-spies" target="_blank" rel="noreferrer noopener">auto-spies</a> to set up the input <em>Observables</em>. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">let loadPostActionSpy$ = createObservableWithValues(
    [
        { value: { postIds: [5,6,7] } },
        { value: { postIds: [8,9,10] }, delay: 1000 },
        { complete: true },
    ],
    { returnSubject: true }
);
const loadPostAction$ = loadPostActionSpy$.values$;

const postServiceSpy = createSpyFromClass(PostService);
const commentServiceSpy = createSpyFromClass(CommentService);

postServiceSpy.loadPost.mockImplementation((postId: number): Observable&lt;Post&gt; =&gt; of(
    {id: postId, content: `content of post ${postId}` }
));
commentServiceSpy.loadComments.mockImplementation((postId: number): Observable&lt;string[]&gt; =&gt; of(
    [
        `first comment (${postId})`,
        `another comment (${postId})`
    ]
));</code></pre>



<p>ⓘ Let us see what is going on in the above code:</p>



<ul class="wp-block-list">
<li><code>loadPostAction$</code> is defined with the help of the method <code>createObservableWithValues</code>. This lets us define various emissions and the completion (without marble diagrams 😉) </li>



<li>The <code>createSpyFromClass</code> method of jest-auto-spies is used to mock the implementation.</li>
</ul>



<p>The verification part of the test looks pretty neat as you are going to see below. By using <code>subscribeSpyTo</code> we can create an <code>observerSpy</code> that lets us continuously check the values. Various methods are available (see <a href="https://github.com/hirezio/observer-spy#const-observerspy--subscribespytoobservable" target="_blank" rel="noreferrer noopener">docs</a>) to test, e.g., all values, just the last ones, or the completion.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const observerSpy = subscribeSpyTo(result$);

// some intermediate verification for posts 5,6,7
expect(observerSpy.getValues()).toEqual(expectedPosts);

await observerSpy.onComplete();

expect(observerSpy.getLastValue()?.id).toEqual(10);
expect(observerSpy.receivedComplete()).toBe(true);</code></pre>



<p>Let us also list the most important characteristics of this RxJS testing approach:</p>



<ul class="wp-block-list">
<li>✍ Auto-spies combined with observer-spy offer similar capabilities to <em>rxjs-marbles</em> without the need to define the marble diagrams.</li>



<li>⏱ Some timing can be defined (see <em>createObservableWithValues</em>).</li>



<li>✅ Verification does not involve any nesting or additional data structures.</li>



<li>😊 Checking values feels reasonable. We can access and check the parts we are interested in. </li>
</ul>



<h2 class="wp-block-heading">Summary</h2>



<p>As so often in web development, we have many different approaches available. Choosing the right one from the RxJS testing approaches depends on many factors. Is the timing of the Observables important for the code under test? Do we only care about the values and the order in which they appear in the output? Especially in larger code bases it is beneficial to choose one approach and stick with it. Otherwise, the code base is not consistent which further confuses developers.</p>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always you can find the code examples on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-testing-approaches-compared/">RxJS Mastery &#8211; Testing approaches compared</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; #69 toArray</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-toarray/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Tue, 26 Dec 2023 09:31:19 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2162</guid>

					<description><![CDATA[<p>Emit all values as an array when the source completes.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-toarray/">RxJS Mastery &#8211; #69 toArray</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="393" src="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_69_toArray-1024x393.png" alt="RxJS toArray" class="wp-image-2163" srcset="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_69_toArray-1024x393.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_69_toArray-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_69_toArray-768x294.png 768w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_69_toArray-1536x589.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_69_toArray.png 1654w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>RxJS <a href="https://rxjs.dev/api/operators/toArray" target="_blank" rel="noreferrer noopener">toArray</a> is another utility operator. It emits all the source values as an array once the source completes.</p>



<h2 class="wp-block-heading">RxJS toArray only works on Observables that complete</h2>



<p>As the toArray operator needs to collect all next notifications, it needs to know when the Observable has completed. Only then we can be sure to have caught all values. This also has impact on the timing of the emission of course.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = cold('abcd|').pipe(
    toArray()
);

expectObservable(result$).toBe(
    '----(r|)',
    {
        r: ['a', 'b', 'c', 'd'],
    }
);</code></pre>



<p>In the above example, the values <code>a, b, c, d</code> are emitted followed by a complete notification. Logically the <code>result$</code> is emitting once at the time the source has completed. </p>



<h2 class="wp-block-heading">Exercise for the RxJS toArray operator 💪</h2>



<p>Collect 3 values each and emit them as an array repeatedly. You might want to look into the repeat and delay operators.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const result$ = interval(1).pipe(
    // a combination of toArray, take, delay and repeat
);

expectObservable(result$).toBe(
    '----w---x---y---(z|)',
    {
        w: [0, 1, 2],
        x: [0, 1, 2],
        y: [0, 1, 2],
        z: [0, 1, 2],
    }
);</code></pre>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-toarray/">RxJS Mastery &#8211; #69 toArray</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; #68 timeInterval, timestamp, timeout</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-68-timeinterval-timestamp-timeout/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 17 Dec 2023 10:36:32 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2146</guid>

					<description><![CDATA[<p>Deal with time things.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-68-timeinterval-timestamp-timeout/">RxJS Mastery &#8211; #68 timeInterval, timestamp, timeout</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="395" src="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_68_time-1-1024x395.png" alt="" class="wp-image-2155" srcset="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_68_time-1-1024x395.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_68_time-1-300x116.png 300w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_68_time-1-768x296.png 768w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_68_time-1-1536x592.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_68_time-1.png 1608w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>RxJS offers some time operators in the utility category. In this article, we are going to have a look at <a href="https://rxjs.dev/api/operators/timeInterval" target="_blank" rel="noreferrer noopener">timeInterval</a>, <a href="https://rxjs.dev/api/operators/timestamp" target="_blank" rel="noreferrer noopener">timestamp</a>, <a href="https://rxjs.dev/api/operators/timeout" target="_blank" rel="noreferrer noopener">timeout</a>, and <a href="https://rxjs.dev/api/operators/timeoutWith" target="_blank" rel="noreferrer noopener">timeoutWith</a>.</p>



<h2 class="wp-block-heading">RxJS timeInterval measures the time between two values</h2>



<p>The timeInterval operator emits an object containing not only a value but also the time that has passed since emitting the previous value. The easiest example is probably the one based on <a href="https://ronnieschaniel.com/rxjs/rxjs-lessons-interval/">interval</a>.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">interval(1000)
    .pipe(take(4), timeInterval())
    .subscribe({ next: x => console.log(x), complete: done});

// TimeInterval { value: 0, interval: 1004 }
// TimeInterval { value: 1, interval: 1047 }
// TimeInterval { value: 2, interval: 1010 }
// TimeInterval { value: 3, interval: 1006 }</code></pre>



<p>Be aware that intervals are non-deterministic and it is not always going to be a 1000 ms. Also with rxjs marbles, we can nicely show the behavior. You might notice that the complete notification is not considered:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const timeMeasured$ = cold('100ms a 200ms b 300ms c 400ms |').pipe(
    timeInterval(),
    map((v: TimeInterval&lt;string>) => v.interval),
);

expectObservable(timeMeasured$).toBe(
    '100ms a 200ms b 300ms c 400ms |',
    {
        a: 100,
        b: 201,
        c: 301,
    }
);</code></pre>



<p>Also, the emission itself takes 1 ms. Therefore the time between is 201 ms or 301 ms.</p>



<h2 class="wp-block-heading">RxJS timestamp attaches the datetime to an emission</h2>



<p>The timestamp operator simply creates the current date, usually with <code>Date.now()</code>, and attaches it to the emission. The value emission therefore looks like this: <code>{value: T, <a href="https://rxjs.dev/api/index/function/timestamp">timestamp</a>: R}</code>.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">interval(1000)
    .pipe(take(4), timestamp())
    .subscribe({ next: x => console.log(x), complete: done});

// { value: 1, timestamp: 1702807174323 }
// { value: 2, timestamp: 1702807175327 }
// { value: 3, timestamp: 1702807176335 }</code></pre>



<p>You see in the output the value alongside the UNIX timestamp. Again we can have a look at the situation when using the TestScheduler and marbles:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">createTestScheduler().run((helpers) => {
    const { expectObservable, cold } = helpers;

    const timeStamped$ = cold('100ms a 200ms b 300ms c 400ms |').pipe(
        timestamp(),
    );

    expectObservable(timeStamped$).toBe(
        '100ms a 200ms b 300ms c 400ms |',
        {
            a: { value: 'a', timestamp: 100 },
            b: { value: 'b', timestamp: 301 },
            c: { value: 'c', timestamp: 602 },
        }
    );
});</code></pre>



<p>Thanks to the TestScheduler the time is not based on the AsyncScheduler&#8217;s <code>Date.now()</code>. Time starts at 0 and adds up nicely.</p>



<h2 class="wp-block-heading">RxJS timeout errors if values do not arrive in time</h2>



<p>The timeout operator allows to throw an error should too much time pass until a value is emitted. In the below example, we specify a timeout of 250 ms. Therefore the value <code>c</code> has no chance of being emitted 300ms after the value <code>b</code>. Instead, a <code>TimeoutError</code> is thrown.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const timeout$ = cold('100ms a 200ms b 300ms c 400ms |').pipe(
    timeout(250),
);

expectObservable(timeout$).toBe(
    '100ms a 200ms b 249ms #',
    {
        a: 'a',
        b: 'b',
    },
    new TimeoutError(),
);</code></pre>



<p>The timeoutWith operator is deprecated and the timeout operator itself offers a with parameter in the TimeoutConfig. This helps us to specify how we want to time out. We can for example define a custom error instead of the <code>TimeoutError</code>.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">class CustomTimeoutError extends Error {
    constructor() {
        super('It was too slow');
        this.name = 'CustomTimeoutError';
    }
}

createTestScheduler().run((helpers) => {
    const { expectObservable, cold } = helpers;

    const timeout$ = cold('100ms a 200ms b 300ms c 400ms |').pipe(
        timeout({
            each: 250,
            with: () => throwError(() => new CustomTimeoutError())
        }),
    );

    expectObservable(timeout$).toBe(
        '100ms a 200ms b 249ms #',
        {
            a: 'a',
            b: 'b',
        },
        new CustomTimeoutError(),
    );
});</code></pre>



<p>Note that we have to pass a TimeoutConfig object in this case where the timeout value is defined in the <code>each</code> parameter.</p>



<h2 class="wp-block-heading">Exercise for the RxJS timeout operator 💪</h2>



<p>The timeout operator not only allows to specify a custom error in the <code>with</code> parameter. But it also enables us to switch to a different Observable entirely. That way we can switch to a faster Observable on timeout. This is exactly the task for you. When the timeout occurs you should replace the Observable with something that fulfills the below marbles diagram:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const timeout$ = cold('100ms a 200ms b 300ms c 400ms |').pipe(
    timeout({
        each: 250,
        with: // your code
    }),
);

expectObservable(timeout$).toBe(
    '100ms a 200ms b 249ms c 100ms |',
    {
        a: 'a',
        b: 'b',
        c: 'c'
    },
);</code></pre>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-68-timeinterval-timestamp-timeout/">RxJS Mastery &#8211; #68 timeInterval, timestamp, timeout</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; #67 subscribeOn</title>
		<link>https://ronnieschaniel.com/rxjs/rxjs-mastery-subscribeon/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 17 Dec 2023 09:04:15 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2138</guid>

					<description><![CDATA[<p>Allows to specify the scheduler with which subscriptions happen.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-subscribeon/">RxJS Mastery &#8211; #67 subscribeOn</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="392" src="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_67_subscribeOn-1024x392.png" alt="" class="wp-image-2139" srcset="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_67_subscribeOn-1024x392.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_67_subscribeOn-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_67_subscribeOn-768x294.png 768w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_67_subscribeOn-1536x588.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_67_subscribeOn.png 1652w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The RxJS <a href="https://rxjs.dev/api/operators/subscribeOn" target="_blank" rel="noreferrer noopener">subscribeOn</a> operator returns the source Observable in a modified state such that the subscription happens with a specified scheduler.</p>



<h2 class="wp-block-heading">RxJS subscribeOn to customize the emission of values</h2>



<p>As schedulers control the speed and order of emissions, this can help to customize an existing Observable to one&#8217;s needs. Let us see that in action. The <a href="https://ronnieschaniel.com/rxjs/rxjs-lessons-of/">of</a> operator synchronously emits values. We can change that by specifying the <a href="https://rxjs.dev/api/index/const/asyncScheduler" target="_blank" rel="noreferrer noopener">asyncScheduler</a> with the help of subscribeOn.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const a$ = of(1, 2, 3).pipe(subscribeOn(asyncScheduler));
const b$ = of(4, 5, 6);

merge(a$, b$).subscribe(console.log);</code></pre>



<p>The output of the above code does not start with 1, 2, 3. But it looks like the following:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">4
5
6
1
2
3</code></pre>



<p>Because the values of <code>b$</code> are emitted synchronously they come first. On the other hand, the values of a$ are put onto the event loop of JavaScript and therefore appear asynchronously.</p>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-subscribeon/">RxJS Mastery &#8211; #67 subscribeOn</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RxJS Mastery &#8211; #66 observeOn</title>
		<link>https://ronnieschaniel.com/rxjs/observeon/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sat, 16 Dec 2023 14:09:49 +0000</pubDate>
				<category><![CDATA[RxJS]]></category>
		<category><![CDATA[RxJs Lessons]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2122</guid>

					<description><![CDATA[<p>Specify a scheduler for all the notifications from the source.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/observeon/">RxJS Mastery &#8211; #66 observeOn</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="391" src="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_66_observeOn-1024x391.png" alt="" class="wp-image-2124" srcset="https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_66_observeOn-1024x391.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_66_observeOn-300x115.png 300w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_66_observeOn-768x293.png 768w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_66_observeOn-1536x587.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2023/12/rxjs_66_observeOn.png 1654w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The RxJS <a href="https://rxjs.dev/api/operators/observeOn" target="_blank" rel="noreferrer noopener">observeOn</a> operator remits all notifications from the source using a specified scheduler.</p>



<h2 class="wp-block-heading">RxJS observeOn with animationScheduler for smooth animations</h2>



<p>If the scheduler of the source Observable cannot be adapted, the observeOn operator comes into play. The primary use case for the RxJS observeOn operator is the specification of the animationScheduler for certain Observables.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">const progressBarDiv = new HTMLDivElement();

interval(10)
    .pipe(observeOn(animationFrameScheduler))
    .subscribe(newHeight =&gt; {
        progressBarDiv.style.height = newHeight + 'px';
    });</code></pre>



<p>This helps to get rid of choppy animations because the value emission is better synchronized with the rendering behavior of the browser:</p>



<figure class="wp-block-video mt-2"><video height="858" style="aspect-ratio: 1732 / 858;" width="1732" controls poster="https://ronnieschaniel.com/wp-content/uploads/2021/09/scheduler_video_poster_image.png" src="https://ronnieschaniel.com/wp-content/uploads/2021/09/scheduler_smooth_browser_animation.mov"></video></figure>



<h2 class="wp-block-heading">Prefer the delay operator over the delay parameter of observeOn</h2>



<p>In addition to the scheduler parameter, observeOn would also support a delay. This delay is applied to every source notification, including errors.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">observeOn&lt;T&gt;(scheduler: SchedulerLike, delay: number = 0): MonoTypeOperatorFunction&lt;T&gt;</code></pre>



<p>This is the main reason why the <a href="https://ronnieschaniel.com/rxjs/rxjs-mastery-delay-delaywhen/">delay</a> operator is recommended over the delay parameter of observeOn. Usually, you do not want to delay errors. Besides the delay operator is also better understood.</p>



<p>This post is part of the <a href="https://ronnieschaniel.com/tag/rxjs-lessons/">RxJS mastery series</a>. As always the code examples can be found on <a href="https://github.com/rschaniel/rxjs_in_x_lessons" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/rxjs/observeon/">RxJS Mastery &#8211; #66 observeOn</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		<enclosure url="https://ronnieschaniel.com/wp-content/uploads/2021/09/scheduler_smooth_browser_animation.mov" length="1380767" type="video/quicktime" />

			</item>
	</channel>
</rss>
