我正在关注英雄示例的 Angular 之旅,并以相同的方式构建了(我认为)我的代码版本,但没有收到我期望的行为。
import { Injectable } from '@angular/core';
import { PORTS } from './mock-ports'
import { Port } from './port'
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UpdateportsService {
private controller_url = '/gelante/getports/150013889525632'
private controller_ip = 'http://localhost:8080'
getPorts(): Observable<Port[]> {
return this.http.get<Port[]>(this.controller_ip + this.controller_url)
}
constructor(private http: HttpClient) { }
}
Run Code Online (Sandbox Code Playgroud)
const myObserver = {
next: x => console.log('Observer got a next value: ' + x),
error: err => console.error('Observer got an error: ' + err),
complete: () => console.log('Observer got a complete notification'),
};
Run Code Online (Sandbox Code Playgroud)
// This is part of the same class as getPorts
ports: Port[] = [];
getPorts(): void {
// To subscribe to an observable, you take the declared observable, which in
// this case is getPorts (which returns an array of ports) and then you
// subscribe to it. Anytime the observable is called it will emit values
// which are then sent to all subscribers.
console.log(this.ports)
this.updateportsService.getPorts().subscribe(ports => this.ports = ports);
// This prints all of my port data as expected
this.updateportsService.getPorts().subscribe(myObserver);
console.log(this.ports)
}
Run Code Online (Sandbox Code Playgroud)
Array(0) []
switch.component.ts:76
Array(0) []
switch.component.ts:82
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
core.js:40917
Observer got a next value: [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
switch.component.ts:13
Observer got a complete notification
switch.component.ts:15
[WDS] Live Reloading enabled.
Run Code Online (Sandbox Code Playgroud)
目标是获取我从 REST API(与 Angular 分开)接收到的交换机接口列表,并将它们分配给称为端口的字典列表。这应该在以下行中完成:
this.updateportsService.getPorts().subscribe(ports => this.ports = ports);
在《英雄之旅》示例中,应该填充函数 getPorts 中的端口。我已经从 Wireshark 和一些调试输出中确认 HTTP get 请求正在按预期运行。具体来说,你可以看到这一行:
this.updateportsService.getPorts().subscribe(myObserver);
它接收大量对象(如预期)。然而,无论出于何种原因,分配ports => this.ports = ports似乎不起作用。ports 的值始终是一个包含零个元素的空数组。但是,我一直无法弄清楚为什么。
这是一个在赋值之前尝试访问异步数据的简单情况。在本例中,this.ports是异步分配的。因此,当您这样做时console.log(this.ports),它还没有被分配任何值。但是当您使用myObserver它时,它会起作用,因为您正在订阅内打印,正如它应该的那样。完全等效的使用ports如下
this.updateportsService.getPorts().subscribe(
ports => {
this.ports = ports;
console.log(this.ports);
},
error => {
// it is always good practice to handle error when subscribing to HTTP observables
}
);
Run Code Online (Sandbox Code Playgroud)
请参阅此处了解有关异步请求的更多信息。
async控制器中的管道与订阅
async在大多数情况下建议使用管道,因为它负责取消订阅可观察量以避免内存泄漏问题。当手动订阅可观察对象时,最好在钩子中取消订阅OnDestroy。
import { Subscription } from 'rxjs';
export class AppComponent implements OnInit, OnDestroy {
obsSubscription: Subscription;
ngOnInit() {
this.obsSubscription = this.service.observable.subscribe(value => { // handle value });
}
ngOnDestroy() {
if (this.obsSubscription) {
this.obsSubscription.unsubscribe();
}
}
}
Run Code Online (Sandbox Code Playgroud)
通常unsubscribe在使用时会被忽略,HttpClient因为它处理取消订阅并避免内存泄漏。但也有例外。例如,如果用户离开进行 HTTP 调用的链接,该链接可能仍处于打开状态。所以始终建议手动关闭订阅。
还有另一种优雅的方式使用 来处理取消订阅takeUntil。
import { Subject, pipe } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export class AppComponent implements OnInit, OnDestroy {
closeActive = new Subject<void>();
ngOnInit() {
this.obsSubscription = this.service.observable
.pipe(takeUntil(this.closeActive))
.subscribe(value => { // handle value });
}
ngOnDestroy() {
this.closeActive.next();
this.closeActive.complete();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2235 次 |
| 最近记录: |