如何在Angular 12中使用Observables?

539 阅读6分钟

如何在Angular 12中使用Observables

当涉及到异步编程或处理事件的时候,JavaScript的概念Observables是非常关键的。

在Angular应用程序中,只要需要消息传递,它们就会发挥重要作用。

在本教程中,我们将讨论Angular观测器的概念,了解它们是什么,如何在Angular应用程序中使用它们,并最终建立一个示例项目。

前提条件

要跟上这个教程,你需要。

  • 具备JavaScript的基本知识(TypeScript可能会派上用场)。
  • 具备Angular 2+的基本知识。在本教程中,我们使用Angular 12版本。
  • 本地开发环境设置。确保你有Angular CLI来帮助你设置环境。
  • 反应式编程的基本概念,特别是RxJs
  • 另外,之前在Promise方面的知识也很重要,但不是必须的。

开始使用观测器

一个Observable是一个类似于Promise的独特而直接的Object,可以帮助管理异步代码。

在讨论可观察对象的概念时,我们可能会想到一个带有通讯表单的Web应用,其中订阅者会收到消息,而非订阅者则不会。

这是一种在应用程序中定义方法的声明性方式,用于发布指定的值,在消费者订阅之前不会被执行。

在讨论可观察变量时,我们不断与之互动的一个概念是观察者的使用。观察者被用于定义函数,在本例中,(回调函数)。这些方法包括next(),error(), 和complete()

观察者对象通常作为参数传递给可观察方法。然后,由于事件等触发因素,可观察函数会调用这些观察者函数。

JavaScript可观察的样本

有了观察者的基本概念,让我们来实现一个观察者类的样本,深入了解它们的工作原理。

打开index.js 文件,添加以下内容。

//define observable class here
class ObservableExample {
    //class constructor
    // add the argument to pass the function to take the observer
    constructor(methodToTakeObserver){
      this._methodToTakeObserver_ = methodToTakeObserver;
    }
    // add a subscriber method and pass observer as argument
    // this method returns function that takes an observer
    subscribe(observer) {
      return this._methodToTakeObserver_(observer)
    }
}
// create an instance of the observer class we defined above
let myObservableExample = new ObservableExample(observer => {
  setTimeout(() => {
    // observer next data executed after 5s
    observer.next("I have got the response!")
    observer.complete()
  }, 5000)
})
//

let myObserverExample = {
  next(response) {
    console.log(response)
  },
  error(err) {
    console.log(err)
  },
  complete() {
    console.log("The request has been completed successfully")
  }
}

myObservableExample.subscribe(myObserverExample)
// Upon execution
// (5 seconds) I have got the response!
// (5 seconds ) The request has been completed successfully

observer response

你会注意到在上面的脚本中,我们定义了我们的类和它的构造函数。然后我们继续向这个构造函数传递一个参数。

然后我们继续定义另一个函数,subscriber() 。它接受一个参数 observer,然后把它传递给我们定义的构造函数。

接下来,我们实例化我们的类ObservableExample ,然后将其分配给我们的局部变量myObservableExample

在此之前,我们已经为这个类创建了一个构造函数;因此我们把观察者作为一个参数函数传入。

此外,我们使用了定时器方法,因为我们假设一个HTTP响应需要一定的时间,因此要模仿。在我们的案例中,我们使用了一个相当糟糕的情况,即5s。

值得注意的是,来自服务器的响应可能需要一些时间才能到达。因此,我们使用了setTimout() 方法来模仿这个功能。你不妨设置符合你要求的时间。

你可能还记得,我们讨论过,观察者有一些方法。在这种情况下,我们调用next()complete() 操作。

最后,我们实现我们的观察者发送的回调函数。然后,每当有订阅发生时,我们就运行我们的观察者(通过subscribe() 方法)。

输出。

// Upon execution
// ( 5 seconds) I have got the response!
// (5 seconds ) The request has been completed successfully

设置项目

现在我们已经掌握了纯JavaScript中观察器的基本概念,让我们继续进行并设置我们的Angular 12项目。

首先,打开终端(Ctrl+Alt+T),并运行以下命令。

ng new observable-example

project-setup

接下来,通过运行以下命令创建一个可观察组件。

ng g component observable

为了确保可观察组件的有效工作,请编辑app.component.html ,如下图所示。

<app-observable></app-observable>

上述元素可以确保,无论何时我们编辑我们的观察者组件,变化都会反映在浏览器上,因为我们使用的是app组件作为我们的根。

现在,你的组件已经完全发挥作用了

在Angular中定义和创建观察者

在Angular中创建一个观察者是很简单的,不像前面的例子,我们从头开始定义一切。

在这里,我们从RxJs中调用已经定义好的类Observable ,然后传递必要的参数,我们很快就会看到。

通过运行以下命令创建一个API服务。

ng g service api

接下来,继续并编辑该服务,如下图所示。

// edit the api.service.ts file
import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";//notice we import the observable from RxJS

@Injectable({
  providedIn: 'root'
})
// define our class constructor
// inject the http client (Dependency injection)
constructor(private httpClient:HttpClient) { }

// a method to fetch all clients from some server 
public getAll(): Observable<any>{
   return this.httpClient.get('http://127.0.0.1:8080/api/clients');
 }

我们定义了上述服务,因为我们在Angular中进行API请求时主要与可观察的概念进行交互。

我们在上述代码中注入HTTP客户端,它向远程服务器发出API请求。

接下来,我们现在确定我们的API会返回一个可观察变量。

为了订阅这个可观察的东西,我们现在来编辑可观察的组件,如下图所示。

//edit the observable.component.ts file as follows
import { Component, OnInit } from '@angular/core';
import {ApiService} from "../api.service";
import {Observable} from "rxjs";
import {User} from "../user";

@Component({
  selector: 'app-observable',
  templateUrl: './observable.component.html',
  styleUrls: ['./observable.component.css']
})
clients$: Observable<User[]>
  constructor(private apiService:ApiService) { }

  ngOnInit(): void {
  }

  /**
   * get all users
   */
  getClients(){
    this.apiService.getAll()
      .subscribe(data => {
        this.clients$ = data;
      })
  }

接下来,编辑模板以列出客户,如下所示。

<!--edit the observable.component.html template as follows -->
<h3>Clients List</h3>
<ol>
    <li *ngFor="let client of clients$">
        {{ client.first_name }} {{ client.last_name }}
    </li>
</ol>

你从上面的脚本中注意到,我们正在导入我们之前创建的服务。

然后我们使用依赖性注入的概念将这个服务注入到我们的组件构造器中。

我们还创建了一个User 接口,作为我们的用户模型。然后我们定义了公共属性clients$ ,后缀为$ ,以表明它是可观察的。

值得注意的是,用后缀$ 来定义一个可观察的属性并不是必须的。这只是一个建议,以确保我们的代码保持干净。

接下来,我们定义方法getClients() 。使用这个方法,我们对其进行订阅,这样,每当我们收到用户的列表时,我们就会得到这个值,并将其传递给clients$ 这个公共变量。

我们也可以修改getClients() 方法来处理API可能产生的错误。

 getClients(){
    this.apiService.getAll()
      .subscribe(data => {
        this.clients$ = data;
      }, error=>{
          console.log(error);
      })
  }

请注意,我们把响应和错误都作为回调传递,因为我们在上一节手动定义了它们。

好吧,这只是在Angular中使用可观察变量的一种方式。

另一种方法是在模板中使用管道,我们很快就会学到。

// define another method in the observable.component.ts  file
  getClients2(){
    this.clients$ = this.apiService.getAll();
  }

这种方法比前一种方法更有效的原因是,它避免了内存泄漏,因为我们的订阅没有被打开。

此外,这种方法确保我们不必担心我们的订阅管理,因为它是由应用程序为我们处理的。

现在我们明白了这个方法的重要性,让我们编辑我们的模板,以确保在我们组件的生命周期中的订阅。

<ol>
    <li *ngFor="let client of clients$ | async">
        {{ uclientser.first_name }}  {{ client.last_name }}
    </li>
</ol>

请注意,我们使用的是async 管道。这个异步管道确保了我们的观测器的自动subscribe/unsubscribe 操作。

定义手动观测器

之前,我们为观测器定义了我们的类,并进行了基本的示例。

然而,JavaScript有一个库,RxJS(Reactive Extension for Javascript),我们可以用它来处理我们的观察变量。

现在,创建一个文件,index.ts ,并按照下面的描述进行编辑。

//import an observable from the rxjs
import { Observable } from "rxjs/Observable"
// next, create observable
const exampleObservable = new Observable((observer) => {}

在定义了上述实例之后,你可以按照我们之前的例子来实现符合你需求的观察变量。

总结

本文探讨了JavaScript、TypeScript和Angular中的可观察变量的概念。

我们已经看到了如何创建一个样本类来构建我们的观察变量。然而,我们也注意到了在TypeScript中构建观察变量的其他方法。

这涉及到反应式编程概念的使用,即RxJS。

此外,我们还看到了如何在Angular中订阅我们的观察变量。这涉及到在组件中使用管道和开放订阅。