In the recent Asynchronous Processing in ES6 web development tutorial, we learned one way to process several asynchronous calls in a row using the static Promise.all() method. It combines an iterable of promises into a single promise that provides the amalgamated results as a single array. Since that article was published, several people have asked me if there was a pure RxJS alternative to accomplish the same thing that did not rely on promises. The answer, as we will see in this tutorial, is a resounding yes! While we are at it, we will be covering how to bind asynchronous data to a local variable, such as one that stores an ID, so that all information for a given entity is kept together. Otherwise, processing numerous RxJS calls within a single subscribe() callback can result in both nasty and insidious mangling of continuity. To demonstrate how and why that can happen, we will fetch a list of link labels twice, both with and without data binding, and witness the very different outcomes.
Before moving forward, you may want to revisit (or read) Asynchronous Processing in ES6.
The solution presented in the Asynchronous Processing in ES6 tutorial employed the Promise.all() method to test the validity of several links. Here is that method again, for the purposes of recapitulation:
There is nothing wrong with the above code per se; it works exactly as intended. There is, however, no guard against memory leaks, such as we might unwittingly produce if we were to navigate to another page. In that case, the subscription would live on even after the component was destroyed, so that, navigating back to the page would again invoke the component constructor and spawn a new subscription.
Meanwhile, using RxJS operators comes with its own risks, if used incorrectly: mainly that asynchronous payloads could become dissociated from their related ids. To understand how that could occur, observe the following (flawed) solution:
While the above solution ensures that our subscription ends when the component is destroyed, it introduces a whole new issue. The mergeMap operator doesn’t wait for the previous inner Observable to complete before triggering the next inner Observable, allowing multiple inner Observables to emit values in parallel. Under heavy load, or with rapid-fire calls, it’s possible for requests to be processed out of order!
A far better approach is to use forkJoin. It runs all observable sequences in parallel and collects their last elements. This means that the operator gets values from completed observables and returns a completed observable with single value. This both preserves the original order and makes unsubscribing unnecessary! Notice how much simpler the following implementation is compared to the last one:
Read: RxJS Observables Primer in Angular
By now it should be apparent that storing local ids and fetched associated data as separate parallel arrays is not the most robust approach. In asynchronous processing, object attributes should be kept together as much as possible. With that in mind, let’s refactor the forkJoin code to store both the link id and name in one object.
First, let’s define an interface that outlines the object structure:
We can now declare an array of Links:
Now to fetch the link names the CORRECT way, so that the ids and names are associated together. To do that, we’ll pipe the output of getLinkName() to the RxJS map operator. In addition to receiving the linkName as a parameter, the map’s callback function also has access to the linkId thanks to the closure formed by outer Array.map’s callback function:
Read: Executing RxJS Observables in Order
Storing link data in objects affects how we access it within the template. Previously, link names were associated with their ids using the loop index, which was passed to the getLinkInfo() method:
Storing link data in objects eliminates the need for a loop index as we can pass the object directly to getLinkInfo(). The link name is accessible via the link object’s name attribute:
Having all link attributes within the same object makes the getLinkInfo() method’s job much easier as well:
On codepen.io, you’ll find a demo that puts the mergeMap and forkJoin RxJS solutions together for easy comparison. Watch what happens when we click one of the links in the first (bad) row:
Due to the inclusion of link ids in their names, it’s easy to spot the incongruities. Were the ids not part of the link names, the mismatch could go on until someone realized something was amiss!
In this tutorial we got a double whammy of RxJS goodness: how to process several asynchronous calls in a row using RxJS operators while binding fetched data to their ids, so that all information for a given entity is kept together.
Advertise with TechnologyAdvice on HTMLGoodies and our other developer-focused platforms.
Property of TechnologyAdvice.
© 2022 TechnologyAdvice. All Rights Reserved
Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.
Hire me on the World’s Leading Online Marketplace Freelancer.com to design your website. Additional services like- graphic design, virtual assistance, SEO, Data entry, etc are available. Click on This Link to start your project