Hey, I am Sean, and work with a very small team of developers. We run a web application that helps a business manage their everyday Health and Safety operations. Using Angular as the client-side framework gives you all sorts of helpful things right out the box and although it has n slight learning curve, it’s really not that bad to get your head around the main concepts of Single Page Applications.
嗨,我是肖恩(Sean),与一个非常小的开发人员团队一起工作。 我们运行一个Web应用程序,以帮助企业管理其日常健康与安全运营。 将Angular用作客户端框架可以为您提供各种有用的功能,尽管它几乎没有什么学习曲线,但是让您了解单页应用程序的主要概念确实不是那么糟糕。
According to the Angular documentation, the recommended technique for handling event data, asynchronous programming, and multiple values is Observables. In this article, we will look into how we use rxjs operators to interact with observables.
根据Angular文档 ,用于处理事件数据,异步编程和多个值的推荐技术是Observables。 在本文中,我们将研究如何使用rxjs运算符与可观察对象进行交互。
Okay, finally I can get to the point here. Using subscribe() is a really easy way to get our values from our observables. Once you read up on all of this you will learn that subscribing comes with its own problems. Scary words come up in articles. People mention things like ‘memory leaks’ and you start wondering if you really know what the fuck you’re doing.
好吧,终于可以在这里了。 使用subscription()是从观察对象中获取我们的价值的一种非常简单的方法。 阅读完所有这些内容后,您将了解到订阅有其自身的问题。 文章中出现可怕的词语。 人们提到诸如“内存泄漏”之类的东西,然后您开始怀疑您是否真的知道自己在做什么。
Although it can all become very confusing I want to use a few real-world and simple examples of how I have implemented the rxjs library in our application. Note that this is just from what I have learned, if you feel I left something out then please comment and help me learn something.
尽管这一切都变得非常令人困惑,但我想使用一些实际的简单示例来说明如何在应用程序中实现rxjs库。 请注意,这只是从我中学到的知识,如果您觉得我遗漏了一些东西,请发表评论并帮助我学习一些东西。
anyway…
无论如何…
In this example, we are going to fetch a collection of answer types from our API and display the information in a drop-down box. We use the HttpClient Module provided to us by the Angular Framework. This call will be done from the component using a method in our service file. The HttpClient will return an observable that hold the values we requested from the api.
在此示例中,我们将从API中获取答案类型的集合,并将信息显示在下拉框中。 我们使用Angular框架提供给我们的HttpClient模块。 该调用将使用服务文件中的方法从组件完成。 HttpClient将返回一个可观察值,其中包含我们从api请求的值。
Your service will have something like this:
您的服务将具有以下内容:
getAnswerTypes() {return this.http.get<any>(`${environment.apiUrl}/checklist/answer-types`);}
And we will call this method from our component doing this:
然后我们将从组件中调用此方法:
this.checklistService.getAnswerTypes()
This will now return an observable. To get the data we need to display on the front end we have two options.
现在这将返回一个可观察的。 为了获得我们需要显示在前端的数据,我们有两个选择。
Manually subscribe/unsubscribe
手动订阅/退订
Option one is what we have been doing in our code up till now. You can use subscribe to get the result and then assign those values to a property on your component. This way the values are ready to use in your template once the request has completed. This approach does come at the small cost of unsubscribing in your component’s ngOnDestroy lifecycle hook. That feels like a lot of work for getting a simple collection and I can promise you that you or someone in your team is going to forget to unsubscribe from something as the application grows.
到目前为止,方案一是我们在代码中一直在做的事情。 您可以使用订阅获取结果,然后将这些值分配给组件上的属性。 这样,一旦请求完成,就可以在模板中使用这些值。 取消订阅组件的ngOnDestroy生命周期挂钩的代价很小。 要获得一个简单的收藏集,这需要大量的工作,我可以向您保证,随着应用程序的增长,您或团队中的某人会忘记取消订阅。
Async Pipe
异步管道
Option two is to use the async pipe that Angular gives us. The async pipe takes care of the subscribing part and then returns the latest value emitted by the observable. The cool thing is that it automatically unsubscribes for us. This is perfect for our specific use case as we do not want to mutate any of the data received from the API, we simply want to pass this on to the template.
方法二是使用Angular给我们的异步管道 。 异步管道负责订阅部分,然后返回可观察对象发出的最新值。 最酷的是它会自动为我们退订。 这对于我们的特定用例来说是完美的,因为我们不想改变从API接收到的任何数据,我们只想将其传递给模板。
We can accomplish this by declaring our property as an Observable in our .ts file:
我们可以通过在.ts文件中将属性声明为Observable来实现此目的:
answerTypes$: Observable<ChecklistAnswerType[]>;
Now we can pass the return value of the http call (which if you remember is an observable) to this answer types property:
现在,我们可以将http调用的返回值(如果您记得是可观察的)传递给此答案类型属性:
this.answerTypes$ = this.checklistService.getAnswerTypes().pipe(map((result) => result.data));
Let’s take a look at what is happening here.
让我们看看这里发生了什么。
The Pipe Function
管道功能
As stated in the docs the pipe
function is the assembly line from your observable data source. The Pipe Function allows you to declare a line of operators that your data set will run through. Think of it as declaring a recipe for your end result. In our example, we use the map operator to tap into the returned API data property from the result. If we wanted to perform any actions on these values we would “chain” more operators.
如docs中所述, pipe
功能是可观察数据源中的装配线。 管道函数允许您声明数据集将要运行的一行运算符。 可以将其视为宣告最终结果的秘诀。 在我们的示例中,我们使用map运算符从结果中挖掘返回的API数据属性。 如果我们想对这些值执行任何操作,我们将“链接”更多的运算符。
Operators
经营者
Operators give you the ability to manipulate the source data and return a new observable of the transformed value. That’s exactly what we are doing. We are receiving an observable, using the map operator to get the data property from the result, and then passing that as an observable to answerTypes$ which is now an observable containing the collection we asked for.
运算符使您能够处理源数据并返回转换后值的新可观察值。 这正是我们正在做的。 我们正在接收一个可观察对象,它使用map运算符从结果中获取数据属性,然后将其作为可观察对象传递给answerTypes $,后者现在是包含我们所要求的集合的可观察对象。
Now we can display our data using the async pipe as explained earlier:
现在,我们可以使用异步管道显示数据,如前所述:
<mat-option *ngFor="let answerType of answerTypes$ | async" [value]="answerType.id">{{ answerType.type }}
</mat-option>
Now we have no subscriptions that we might forget to unsubscribe from. These operators also offer is a nice clean way of mutating our data if we needed to. There are many operators at our disposal and trying to learn them all is a heavy task so I quickly want to mention a few that you will run into regularly.
现在我们没有订阅,我们可能会忘记取消订阅。 如果需要,这些运算符还提供了一种很好的清除数据变异的好方法。 我们有许多操作员供您使用,尝试学习它们都是一项艰巨的任务,因此我想快速提及一些您会经常遇到的问题。
The Map Operator
地图操作员
Map applies a given function to each source and returns the result of that as a new observable. To make this clear, we get a result from the API that looks like this:
Map将给定的函数应用于每个源,并将该结果作为新的可观察值返回。 为了清楚起见,我们从API得到如下结果:
message: "success",
data: [{id: 1, type: "Answer Type 1"}, {id: 2, type: "Answer Type 2"}]
We want to return just the data value and store it on our answerTypes$ property so we use the map operator to access the result and return the data property on it:
我们只想返回数据值并将其存储在我们的answerTypes $属性中,因此我们使用map运算符访问结果并在其上返回data属性:
map((result) => result.data)
Nice and easy…
好,易于…
The Finalize Operator
终结运算符
Finalize will execute the given call back when the observable completes. So if you want something to happen after the data has been manipulated and passed on you can do that in a call back:
当Observable完成时,Finalize将执行给定的回调。 因此,如果您希望在处理和传递数据之后发生某些事情,可以在回调中做到这一点:
this.answerTypes$ = this.checklistService.getAnswerTypes().pipe(map((result) => result.data),
finalize(() => this.servicemanager.setLoading(false)));
Now we have added a second operator to our recipe. Once the map operator has passed the result data we will now tell our service that the http request has been completed and we are no longer loading anything.
现在,我们在配方中添加了第二个运算符。 一旦地图操作员传递了结果数据,我们现在将通知服务我们http请求已完成,并且我们不再加载任何内容。
The Filter Operator
过滤运算符
Filter will return the values that pass a certain condition. To explain this we will use filter to only return the data if the data property exists:
过滤器将返回通过特定条件的值。 为了解释这一点,我们将使用过滤器仅在data属性存在时返回数据:
this.answerTypes$ = this.checklistService.getAnswerTypes().pipe(
filter(result => !!result.data),
map((result) => result.data),
finalize(() => this.servicemanager.setLoading(false)));
Now our recipe also says that only if the data property is part of the result should we continue.
现在,我们的食谱还说,仅当data属性是结果的一部分时,我们才应继续。
It’s not about not subscribing to observables. It’s about knowing when to subscribe to them. Sometimes it is absolutely necessary to subscribe to the results of an API call, when you post some data to the API, you would need to know whether or not that data has been dealt with or if an error occurred. That seems like a good time to subscribe to the result. There are of course ways to handle this re-actively, but this is going to depend on your situation and what actually needs to happen next in your code.
这不是关于不订阅可观察的东西。 关于知道何时订阅它们。 有时,绝对有必要订阅API调用的结果,当您将一些数据发布到API时,您将需要知道该数据是否已处理或是否发生错误。 这似乎是订阅结果的好时机。 当然,有一些方法可以进行响应,但是这将取决于您的情况以及代码中接下来实际需要发生的事情。
The Learn RxJS documentation is extremely helpful and easy to use. Operators are grouped by types and useful examples are given.
Learn RxJS文档非常有用且易于使用。 运算符按类型分组,并给出了有用的示例。
I really hope that this has been useful to someone. If you have any tips on how I can improve this article please let me know using the comments.
我真的希望这对某人有用。 如果您有关于如何改善本文的任何技巧,请使用评论让我知道。
Happy coding everyone!
祝大家编码愉快!
翻译自: https://medium.com/@seankonigphotography/learning-rxjs-3f6b2a8f23e3