Video details

Deborah Kurata: Why Should You Care About RxJS Higher-order Mapping Operators?

Angular
07.01.2020
English

Deborah Kurata

Watch all the ng-conf: Hardwired presentations/videos at www.videos.ng-conf.org.
ng-conf is a three-day Angular conference focused on delivering the highest quality training in the Angular JavaScript framework. 1500+ developers from across the globe converge on Salt Lake City, UT every year to attend talks and workshops by the Angular team and community experts.
Follow us on twitter https://twitter.com/ngconf Official Website: https://www.ng-conf.org/

Transcript

Welcome back. We're going to talk about our stars, higher order mapping operators in this session. We're going to answer a couple of questions. What are higher order mapping operators? When would we ever want to use one? What the heck is an inner observable and what's the difference between map, switch, map, concat, map and merge map? My name's Deborah Kurutz. I'm a software developer and a plural site author. And here's me and one of my favorite places on the planet and I'm sure hoping to be able to go back some day. We'll see how life moves on. With that, I'm ready to jump right in. Let's dive in. So first order versus higher order mapping, first order mapping transforms each embedded value elements. The result? So something like that. We get any more added value into X. We multiply it by two and we get out the results. Higher order mapping transforms each emitted item into another observable. So here we're taking an I.D. So we're getting a stream with. That's going to pre providing us an I.D. and we're transforming that using the HTP get to go retrieve more data, which is going to give us back another observable. So that's the key difference between first order and higher order mapping. Let's dive into that a little bit more, starting with mapping, which is first order. No, not not bad for a store. So when we issue an HDTV, get requests to get some data from a server, we might end up with something like this on the left where we're getting a data property with our array of data. But what we really want is just the array of data. Makes it easier to bind to and to work with. So we can use a map for that. We're going to use an HDTV, get to get the data and then just a map. The response we're getting, which is the data on the left there. And we only want the data properties values, which is our array. So simple enough. Another example of Map Saboor using HDTV, get requests to get one single product. We want to add a property to that product so we can use map for that as well. We're getting the data with an HDTV get. And then we're mapping our product into a copy of the product, using the spread operator and then adding the additional property. So we make a copy of it to ensure that our original product is remains immutable. And then we use as product to ensure that what comes out of our stream is observable of product. One last example of how to use a map. Here again, we have our product on the left that we've retrieved and we want to map it to a string for a display on the top of the page. So how do we do that? We can take our stream back, contained our product, and we can pipe it through here. A simple operation to convert it to a string using the ternary operator. But what if we have something like us? So here is our set of products and the user wants this beautiful ring here, so they click on ring. And what we want to have happen is the detail information to display. So we have a stream set up. When the user clicks on ring, it emits the I.D. of that. So I'd be five, for example. Then it goes and retrieves the data for the detail. Because our list page only has general information, not all of the detailed data. OK. So our first thought might be to do something with a map. So we're going to take our selected I.D. that's emitted into our stream and we're going to map it into a product. Sounds right. So we could write code like this. So we're taking our selected product action dollar, which is getting us this five because that's the one the user picks and we're going to map it into an HDTV, get to go ahead and get the data. But this doesn't work. Bummer. OK. So why? Well, before we answer the why question, let's talk about some terminology. So here's that same code. I just kind of centered on the page. Why doesn't this work? Well, one of the things that we need to understand first is the terminology around us. You know, the first time I've read this in the documentation without actually seeing code, I was quite confused because it said something like when the inner observable emits. And you're like, what the heck is an inner observable? Well, when you're actually looking at the code, it becomes obvious. And then at least I felt kind of silly for not quite getting what an inner observable is. But this part on the outside of the pipe, that's the outer observable piece on the inside is the inner observable. And, you know, again, you look at the center code, that was so obvious. But it isn't if you're just reading documentation and it's talking about the inner observable, like you would know what it was anyway. So outer observable. Inner observable. We're going to use these terms quite a bit for the next couple of minutes. So going back to why this doesn't work, as you know, if you've used anything with our Express in order to make a stream work, you have to subscribe to it. Otherwise, it just doesn't go. You try to issue an HDTV, get request without a subscribe, and it just won't go. And if you're like me sometime at the beginning, you've probably done that where you issue an HDTV queue request. It never works and it's because you haven't subscribed to it. So here in this case, we're going to subscribe to Product Dollar, either with a subscribed statement or with an async pipe subscribing to product Dollar subscribes to what is equal to here. The stuff products selected action. So it starts that stream as well. And we start receiving all of these selection actions. The user clicked on the ring. That's ninety five. We're gonna get the five. We're mapping that to this TTP. Get and get. Guess what we're not doing here. We are not subscribing to that and are observable in this code is never going to run because we're not getting that data. That debt is never going to occur. The other interesting thing is, if you're an editor and you hover over a product dollar, you'll see that its type is observable of observable of product. And, you know, that's just not right. That's not something that you're going to want to deal with or try to unwrap yourself. So how do we deal with that? And the answer is higher order mapping operators. Yay! So let's talk about what those are. A higher order. Mapping operators are a family of operators that ends and map. What they do is they map each value from a source or that outer observable to a new inner observable. But one of the key attributes of higher order mapping operators is that they automatically subscribe and unsubscribe from your inner observable for you so that you don't have to worry about it or mess with it. They then emit their resulting values to the output of surfable. And you get the binding that you're expecting to have. So you might end up with code then that looks like this. So this is the same code that we looked at before, but now we have switch, map instead of map. Now, if you ever go to Stack Overflow and ask any question about our x marks j ust, you will see that a huge portion of the answer is always as uSwitch map, but there are other higher order mapping operators. Then just switch maps and we're going to talk for a moment about what those are. And when you would want to use which one. But having a higher order mapping operator means that it's going to automatically subscribe and unsubscribe from this and are observable in this code is actually going to work. The other thing is, if you hover your mouse over the product dollar there, you will see that it unwrapped it for you as well. So you're going to be getting back unobservable of product, which is what you're going to want for your binding, for your detailed page. OK, so three is the higher order mapping operators that we're going to cover in our session. Here is the merge map, also called Flat Map concat map. And which map? OK, so let's start with merge map. So here again, same code we're using merge map. So what is this going to do? Well, when we subscribe to Product Dollar, it is going to take in that observable or in this case, the product selected, action observable. It's going to subscribe to that stream. So it can get the emissions from that stream. And it's going to create an output stream that it's then going to associate with our product dollar. OK, then when an item is emitted, what it's going to do is it's going to take that item and map it to this and are observable, which is specifies the your LFR htp get that it's going to subscribe to that in or observable. So that sends that off and executes it. Then the inner observably missions are concatenated to that output stream. And it unsubscribed from that observable and we end up with our product dollar observable of product. When should we use merge map anytime we want to process items in parallel? Because what happens with merge map is this. The user picks one and then picks a different one, then picks a different one. It's going to execute those requests right away and process those items in parallel. Now, because it's processing them in parallel and because it's all async, you can't depend on the order of the returned results. Some examples of when to use merge maps say you have a set of ideas and you want to get all of the suppliers for a product when order doesn't matter. It can send off the request for all of them, all at the same time and get all of their values back. The next thing we want to talk about then is can map. Catnaps starts just the same as March map did on the subscribe to the source stream, it takes in the observable stream, subscribes to that stream and creates an output stream. But concat map, unlike Mirch map, when an item is emitted from the stream, it philosophically cues it. So the emitted item is cued up. Then when the item is processed off the queue, at that point, the item is mapped to the entire observable, it subscribes to that in her observable. And another thing different about concat map and Merche map is that it weighs. So this code is going to just stop and wait till that response is returned. Then it's going to concatenated to the output stream and unsubscribes, only then does it take the next one off the queue. So it's going to be processing them one at a time, which is really good if you want to ensure that these are going to happen in sequence. So you want to use concat map any time you actually want to wait for one to finish before starting the next one. The next inter observable, it will process those items in sequence. So a couple of examples on this one from a set of ideas. Get data in sequence or from a set of ideas, update data. You really want to use concat. You really want to consider using Cottonmouth if you're doing any kinds of updates, insert or delete, because you might want them actually in order, say, a user updates a product and then updates that same product. Second time you want to ensure that they are both processed in the order that the user made the updates and can map will help you ensure that happens. All right. The last one we want to talk about then is switch map. Again, the exact same code. Only now we have switch map here. And just like the other higher order mapping operators, that starts the same unsubscribe to the source stream. So when we subscribe to Product Dollar, it subscribes to the sub product selected action. It takes in that observable stream, that product selected action stream subscribes to it and creates an output stream. So that process is the same for all of these operators. When an item is emitted from the source stream, we switch map. The item is mapped to the entire observable. But then what's different from Foote's map than the other two? Is that unsubscribed from any prior in or observable? It then subscribes to the new and are observable. It concatenated the T mission and unsubscribes. So if the user picked four or five, what it's going to do is start to get four. Then it's going to see that five was embedded. It's going to throw away the four. And the subscription for that. And go ahead and process the last selection that the user made. One with idea five. OK. So when would you switch map to stop any prior observable before switching to the next one to process basically the most recent item? For example, type ahead. So if the user typed two letters, you might go off and start searching for something as soon as they type the third. You really don't care about the results from the first two characters. Now you want the results for the three. Another example is user selection from the list, because you if they could pick multiple ones and you only ones ever their last selection to be processed, you want to use a switch map. OK. So our higher order mapping operators are merge map, which executes and are observables in parallel. Concat map, which executed, which waits for each end, are observable to complete and switch maps which unsubscribe from the prior observable before switching to the new one. OK, so now it's time for a quiz. We're going to try out the pulling features here and hopefully this is going to work. You shouldn't see a polling button on the bottom of your screen, kind of near the ask a question. And we're going to have the first question of our quiz come up here momentarily. So this first quiz question is on quick selection. So we've got our list of products on the left. And when the user picks one, we're going to display the detail on the right. But the user could do one song not not leave or not hammer. So they quickly picked three different ones. Only you, of course, only want to display their last one. So on the quiz, define whether you think that's the best operator to use in this case would be a map. Map concat. Map or switch map. All right. So while you're doing that, I'm going to go through each one. So here is the code. Again, that's kind of the same code we've been looking at. And we're going to figure out what mapping operator makes the most sense in this particular case. If we went with a merge map, what would happen is it would start executing all of these in parallel and it's possible if Leif Hreik required a little extra time, maybe it has more detailed data associated with it. It could actually be returned last. You could end up receiving one, three and two. And what would happen then in this case is on the left, the user would look like they said Tammar. But the data on the right would be the leaf break. And then you get a call from a user and you try to repeat it. And, you know, you don't have that same lag for your machine and you don't see it. So it could really cause hard to find and hard to debug issues. So you want to be careful using merge map for these kinds of scenarios. All right, Ken Catnap. What this would do is it would get the first one. Wait till you got it. Depending upon how slow the network is, maybe even display it. Then get the second one. Display that one. Then get the third one and display that one. So the nice thing about concat map over Mirch map is that you would at least end up with always the last one that they picked because they are processed in sequence. But it might take a long time to get there. Depending upon how much that they clicked around and the speed of the connection. What about switch map? Well, what will happen with switch map is when the user clicks saw, it will go try to get saw the user clicks on leaf rank. It's going to cancel the first request and go try to get a leaf break. Then it's going to cancel that request when the user clicks on hammer and it's going to end up just really returning to one. So in this case, switch map was the answer. So which map? So I hope you've got that right. All right. So second quiz, just to show that every answer is as always, which map? Like Stack Overflow sometimes might lead you to believe. We're going gonna look at another example and this is related data. So we've got a second quiz for this one. But let me talk through the scenario here. So in this case, you're still are the user is still picking an item from the left. It's showing the detail on the right. But now, in addition to the detail for the hammer, we're getting the I.D. of the suppliers. And we need to take those ideas and go retrieve the supplier detail because the user doesn't want to see, oh, it's supplier 52 and before they want to actually see the supplier named Data. So the code might look something like this. So we're going to use from to ensure that some observable. We're going to take our supplier I.D. and pipe them through some operator. And for each supplier I.D. that we're processing, we're going to go get the supplier. At the end, we're putting them into an array. Why are we putting them into an array? Because we want to bind to them on the bottom as a single array, not one showing up at a time. To Array will wait for all for the outer observable to complete before it will actually be met as its result. OK, so. Check out the poll and see which operator you think would be correct, your map. Merge map and cat maps. Which map? All right. So what if we used merge map? Well, Wirch mass will go get them all at the same time. So if I had 10 of them, it's going to go issue 10 requests and get all of those back and who knows what order. If we don't care about order, we're going to very quickly get back all the data we need complete. And our for our two array will let us find to the result and we'll see our set of suppliers. All right. What about concat map? Well, what that's going to do is get the first one. Wait for it to finish, then get the next one. Wait for it to finish. And if you had 10 of these, it would be doing them one at a time, waiting for the first one to finish before getting the next one. Now, the nice thing about that is it will retain order. So if you needed these in a particular order for some reason, then concatenate might be a good option. But otherwise it could take you know, if you had ten of them, it could take literally ten times longer than the merge maps to get the data. OK. What about switch maps? What would happen in this case? Well, it would process the first one. See the guesstimated the second one. So cancel that first one. Go to get the second one seed, the third one cancel and so on. Then you'll end up with just one. And I have a little UI there, but basically you would only get one at the end with your array. That last one in the West, which isn't at all what you want. So hopefully what your answer was, was a Mersch map in this case. If you don't care about order, otherwise I can count maps might be your best option. All right. You can find my slides at this link. You can find sample code on my get hub. I also created a stack with such a cool play around with. They demonstrate some of these things. And with that, I want to thank you all very much. They say.